Errors & Retries
When to use
-
You’re defining domain errors and recovery policies
-
You need to map infrastructure errors to domain boundaries
-
You must add retries, backoff, jitter, and timeouts
Model Errors
import { Data } from "effect"
class ValidationError extends Data.TaggedError("ValidationError")<{ field: string; reason: string }>{} class NotFoundError extends Data.TaggedError("NotFoundError")<{ id: string }>{}
Map/Boundary
const repoCall = Effect.fail(new ValidationError({ field: "name", reason: "empty" }))
const service = repoCall.pipe( Effect.mapError((e) => new ServiceError({ cause: e })) )
Recover Precisely
program.pipe( Effect.catchTags({ ValidationError: (e) => Effect.succeed(fix(e)), NotFoundError: (e) => Effect.succeed(defaultValue) }) )
Retry Policies
import { Schedule } from "effect"
const retry = Schedule.exponential("100 millis").pipe( Schedule.jittered, Schedule.compose(Schedule.recurs(5)) )
const resilient = program.pipe(Effect.retry(retry))
Timeouts & Races
const withTimeout = Effect.timeout(program, "2 seconds")
Guidance & Pitfalls
-
Create separate TaggedError types per failure mode; avoid generic Error
-
Map low-level (HTTP/DB) errors to domain errors at the boundary
-
Retry only transient errors (use predicates with Schedule.whileInput )
-
Always combine retry with timeouts for bounded latency
-
Prefer catchTags over broad catchAll for clarity and safety
Real-world snippet: Map HTTP errors and retry selectively
// Verify URL with HEAD-range request, map ResponseError to domain errors, // retry with exponential backoff unless invalid. const verify = http.get(url, { headers: { range: "bytes=0-0" } }).pipe( Effect.flatMap(HttpClientResponse.filterStatus((s) => s < 400)), Effect.catchIf( (e) => e._tag === "ResponseError", (cause) => cause.response.status < 500 ? Effect.fail(new VideoInvalidError({ cause: "NotFound" })) : Effect.fail(new ExternalLoomError({ cause: cause.response })) ), Effect.retry({ schedule: Schedule.exponential("200 millis"), times: 3, while: (e) => e._tag !== "VideoInvalidError" }), Effect.catchTag("RequestError", Effect.die) )
Real-world snippet: Capture structured errors from Cause
import { Cause } from "effect"
const captureErrors = (cause: Cause.Cause<unknown>) => Effect.gen(function* () { if (Cause.isInterruptedOnly(cause)) return { interrupted: true, errors: [] } const raw = captureErrorsFrom(cause) const errors = yield* Effect.forEach(raw, transformRawError({ stripCwd: true })) return { interrupted: false, errors } })
Quick Heuristics
-
Domain errors → TaggedError per type
-
Map low-level to high-level at boundaries
-
Retry only transient errors; predicate with Schedule.whileInput
Cross-links
-
Foundations: operator selection and .pipe style
-
Concurrency: race and timeout patterns
-
EffectPatterns inspiration: https://github.com/PaulJPhilp/EffectPatterns
Local Source Reference
CRITICAL: Search local Effect source before implementing
The full Effect source code is available at docs/effect-source/ . Always search the actual implementation before writing Effect code.
Key Source Files
-
Effect: docs/effect-source/effect/src/Effect.ts
-
Data: docs/effect-source/effect/src/Data.ts
-
Schedule: docs/effect-source/effect/src/Schedule.ts
-
Cause: docs/effect-source/effect/src/Cause.ts
Example Searches
Find error handling patterns
grep -F "catchTag" docs/effect-source/effect/src/Effect.ts grep -F "catchAll" docs/effect-source/effect/src/Effect.ts grep -F "mapError" docs/effect-source/effect/src/Effect.ts
Study TaggedError
grep -F "TaggedError" docs/effect-source/effect/src/Data.ts
Find retry and schedule patterns
grep -F "retry" docs/effect-source/effect/src/Schedule.ts grep -F "exponential" docs/effect-source/effect/src/Schedule.ts grep -F "jittered" docs/effect-source/effect/src/Schedule.ts
Study Cause operations
grep -F "isInterruptedOnly" docs/effect-source/effect/src/Cause.ts
Workflow
-
Identify the error handling API you need (e.g., catchTag, retry)
-
Search docs/effect-source/effect/src/Effect.ts for the implementation
-
Study the types and error recovery patterns
-
Look at test files for usage examples
-
Write your code based on real implementations
Real source code > documentation > assumptions
References
-
Agent Skills overview: https://www.anthropic.com/news/skills
-
Skills guide: https://docs.claude.com/en/docs/claude-code/skills