🔧 Error Fixes
· 2 min read
Last updated on

Effect-TS: Fiber Failure — Defect — How to Fix It


FiberFailure: Error: Defect

What causes this

In Effect-TS, a “Defect” is an unexpected, unhandled error — something your program didn’t anticipate. Unlike expected errors (which you model in the error channel), defects are bugs. They crash the fiber because there’s no handler for them.

Common causes:

  • Throwing a raw JavaScript error inside an Effect without wrapping it
  • A promise rejection that wasn’t caught by Effect.tryPromise
  • Accessing a property on undefined inside an Effect pipeline
  • A third-party library throwing unexpectedly

Fix 1: Use Effect.tryPromise for async operations

import { Effect } from 'effect';

// ❌ Raw promise — unhandled rejection becomes a Defect
const program = Effect.promise(() => fetch('/api'));

// ✅ tryPromise catches rejections as expected errors
const program = Effect.tryPromise({
  try: () => fetch('/api'),
  catch: (error) => new FetchError({ cause: error }),
});

Fix 2: Handle all errors with catchAll

const program = Effect.tryPromise(() => fetch('/api')).pipe(
  Effect.flatMap((res) => Effect.tryPromise(() => res.json())),
  Effect.catchAll((error) =>
    Effect.succeed({ fallback: true, error: String(error) })
  )
);

Fix 3: Use Effect.gen with proper error handling

const program = Effect.gen(function* () {
  const response = yield* Effect.tryPromise(() => fetch('/api'));
  if (!response.ok) {
    return yield* Effect.fail(new ApiError({ status: response.status }));
  }
  const data = yield* Effect.tryPromise(() => response.json());
  return data;
}).pipe(
  Effect.catchTag('ApiError', (e) =>
    Effect.succeed({ error: `API returned ${e.status}` })
  ),
  Effect.catchAll((e) =>
    Effect.succeed({ error: 'Unexpected error', details: String(e) })
  )
);

Fix 4: Catch defects specifically

If you want to recover from defects (not just expected errors):

import { Effect, Cause } from 'effect';

const program = myEffect.pipe(
  Effect.catchAllCause((cause) => {
    if (Cause.isFailure(cause)) {
      // Expected error
      return Effect.succeed({ type: 'expected-error' });
    }
    // Defect — log it and recover
    console.error('Defect:', Cause.pretty(cause));
    return Effect.succeed({ type: 'defect-recovered' });
  })
);

How to prevent it

  • Always use Effect.tryPromise instead of Effect.promise for operations that can fail
  • Model your errors as tagged classes so you can handle them with catchTag
  • Use Effect.sandbox during development to see the full cause of failures
  • Add a top-level catchAllCause in your main program to log defects instead of crashing silently