Handle expected failures without hiding defects

A defect is an unexpected execution failure.

Declare failures that callers can handle. Keep defects distinct from those declared outcomes. Catch a failure where the application can recover or report it truthfully.

Give expected failures a type and useful context

Schema.TaggedError defines a yieldable error: an error a generator can raise with yield*. Its tag identifies the error type; its fields retain context. FileStatsError keeps the path and the filesystem reason.

packages/core/src/stats.ts · 65e9465f
export class FileStatsError extends Schema.TaggedError<FileStatsError>()(
  "FileStatsError",
  {
    path: Schema.String,
    reason: Schema.String,
  }
) {
  override readonly [Runtime.errorExitCode] = 1;
  override readonly [Runtime.errorReported] = false;

  override get message(): string {
    return `Could not read ${this.path}: ${this.reason}`;
  }
}

Inside a generator, return yield* can raise a yieldable error directly. Effect.fail can also place an error in the expected failure channel, the E parameter of the Effect type. Do not throw an ordinary exception to represent a declared refusal.

Translate implementation failures without losing their meaning

The inspector uses Effect.mapError to translate a filesystem failure into its domain error.

packages/core/src/file-inspector.ts · 65e9465f
      const content = yield* fileSystem
        .readFile(path)
        .pipe(
          Effect.mapError(
            (error) => new FileStatsError({ path, reason: error.message })
          )
        );

Translation keeps the failed path and the source message. Callers receive FileStatsError, not a filesystem dependency.

If a domain error needs to carry an unknown source error, Schema.Defect() can describe that field. Such a field does not itself turn an expected error into a runtime defect17.

Recover or report at a named boundary

Effect.catchTag handles the selected failure tag. Other failures remain failed. Use catchTags when several tagged failures need different handlers.

The CLI reports the inspection failure, then fails again:

apps/cli/src/cli.ts · d88169f8
  Effect.catchTag("FileStatsError", (error) =>
    Console.error(error.message).pipe(Effect.andThen(Effect.fail(error)))
  ),

A fallback is appropriate only when its value is a valid domain result. Do not turn a failed inspection into empty file statistics just to complete the command.

Do not use orDie to hide ordinary failures

Effect.orDie removes expected failures from the typed channel by turning them into defects. The inspection machine20 uses it where the machine’s result is handed back to Effect because its expected file failure already travels through the Unreadable outcome. An unexpected actor failure or missing outcome is a programming failure at that boundary.

This is a specific boundary decision. File reads still return FileStatsError to ordinary callers. Use Effect.catchDefect only where an integration boundary must inspect unexpected failures. Do not treat it as general domain recovery.

Common wrong approach

Catching every cause and returning success erases whether the program refused work or crashed. A later caller cannot tell which repair is needed. Keep refusal, unexpected failure, and successful completion distinct.

Effect idiom and house rule

See also: schemas17, author-facing diagnostics8, independent failures9, and lifecycles20.

Sources

  1. Arnaldi, Michael. n.d. Why JavaScript Is Broken: How Effect and TypeScript Fixes It.. Michael Arnaldi. Historical explanation at 23:38 distinguishes failures intended for control flow from defects. Accessed 2026-10-06.
  2. Arnaldi, Michael. n.d. Why JavaScript Is Broken: How Effect and TypeScript Fixes It.. Michael Arnaldi. Historical defect explanation at 25:12; not evidence for current API names. Accessed 2026-10-06.
  3. Effect contributors. 2026. Schema. Effect 4.0.0.. Effect-TS. TaggedError produces yieldable errors; Defect() describes unknown error values in a schema. Accessed 2026-10-06.
  4. Effect contributors. 2026. Effect. Effect 4.0.0.. Effect-TS. mapError translates expected failures; catchTag selects tagged failures; catchDefect and orDie handle different failure boundaries. Accessed 2026-10-06.
  5. rat-stack contributors. 2026. File statistics and failures.. rat-stack. FileStatsError retains the failed path and filesystem reason. Accessed 2026-10-06.
  6. rat-stack contributors. 2026. CLI failure boundary.. rat-stack. The CLI reports a FileStatsError and keeps it failed instead of returning success. Accessed 2026-10-06.
  7. rat-stack contributors. 2026. Inspection lifecycle.. rat-stack. Expected read failure travels through a domain outcome; unexpected actor failure becomes a defect. Accessed 2026-10-06.
  8. Langton, Kit. 2026. Error Handling. Effect Solutions.. Kit Langton. Topic framing for expected failures and defects; older TaggedErrorClass and catchAllDefect names are not used here. Accessed 2026-10-06.

Last changed 2026-10-07 in 989f258. Source on GitHub. Change log.

Linked from

  1. A service captures its construction dependencies. Build a service with its dependencies, then expose methods that callers can use without rebuilding the graph.

    Effect<FileStats, FileStatsError> declares the method’s success and expected failure.

  2. add-a-capability. Learn how one contract and its handler become a command, HTTP route, MCP tool, browser RPC, and sandbox call.

    Effect describes work with typed failures and required dependencies.

  3. add-a-lifecycle-machine. Learn how XState owns a lifecycle while Effect owns its work, errors, and services.

    Effect describes work with typed failures and required dependencies.

  4. add-a-store. Add persistence through a service named for an application job, with validation, vendor Layers, migrations, bounded reads, and shared backend tests.

    Effect describes work with typed failures and required dependencies.

  5. Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.

    Effect describes work with typed failures and required services.

  6. Analytics. One event per HTTP request, stored unchanged for queries to select and interpret later.

    Effect is the library that describes work with typed failures and required services.

  7. Build and run rat-stack (README.md). What is in the repo, how the example works, and how to run it.
    Link context

    7: the official XState v6 to Effect 4 bridge: createEffectActor runs a machine as a scoped Effect, fromEffect makes Effects into actors with typed failures and requirements.

  8. Capabilities. Named application actions exposed through generated interfaces share one definition and one server-side implementation.

    Effect is a library for describing work with typed failures and required services.

  9. Change log. What changed in the files served here, newest first.

    Handle expected failures without hiding defects — edited: fix(lore): re-pin the CLI failure excerpt and link glossary first uses

  10. Code snippets quote a pinned source. Shipped design brief: pinned Git objects, typed diagnostics, and one build-only snippet model for both views.

    The error model separates expected failures from defects.¶

  11. Configuration is a supplied, validated dependency. Parse configuration when a Layer builds, reject invalid values, and supply controlled settings in tests.

    Config parses supplied data and reports typed failures.

  12. Database. One interface records action runs and their outcomes in either Cloudflare D1 or Postgres through Hyperdrive.

    Effect describes work with typed failures and required services.

  13. Devtools. Development-only capabilities inspect calls and lifecycle transitions without entering production bundles.

    Effect describes work with typed failures and required services.

  14. Effect + Alchemy peer patterns. Source-grounded patterns from repos on nearby Effect and Alchemy pins.

    One schema-derived contract carries payloads and typed failures across the wire.

  15. Effect basics. An Effect describes work, expected failures, and required services before a runtime executes it.

    An expected failure belongs in E, where callers can handle it by its declared type or tag.

  16. Effect Office Hours 27: Alchemy, infrastructure as effects. Sam Goodwin presents Alchemy as a system built with Effect for planning, testing, and deploying infrastructure.

    An Effect describes work with typed failures and required services.

  17. Errors are part of the interface. An author error needs a location, the rejected input, and a repair.

    Use the error model to separate expected failures from defects.

  18. Fence. The lint rules, compiler diagnostics, hooks, and gate that make a bad shortcut fail instead of asking an agent to avoid it.

    Effect describes work with typed failures and required services.

  19. find-peers. Refresh public peers, exact stack versions, and usefulness tiers every week or two and after each shared dependency update. Study source before adopting patterns.

    Effect describes work with typed failures and required dependencies.

  20. Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
  21. gardener. Keep rat-stack current and clean. Update exact dependency versions, learn from repos on the same versions, and add lint rules before cleanup.

    Effect describes work with typed failures and required dependencies.

  22. HTTP success needs a status check and a decoder. Supply the client, check the response status, decode accepted data, and name failures at the adapter boundary.

    Read schemas and failures before defining the adapter’s accepted data.

  23. keep-or-cut. Learn which pieces depend on each other, then keep only the ones your project needs.

    Effect describes work with typed failures and required dependencies.¶

  24. Learn mode presents concepts at useful depths. An agent presents source-derived concepts during real work and keeps learning events in a private local log.

    Effect describes the work with typed failures and required services.

  25. learn-alchemy. Learn how Alchemy 2 turns an Effect program into a planned Cloudflare deployment.

    Effect describes work with typed failures and required dependencies.

  26. learn-rat-stack. Trace a capability through Effect, XState, five projections, the CLI, and Alchemy. Try hosted search and read.

    Effect describes work with typed failures and required dependencies.¶

  27. Rat King binds agents into one encrypted network. Rat King plans an encrypted AT Protocol agent network built on rat-stack.

    Effect owns contracts, services, and typed failures.¶

  28. Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.
    Link context

    Handle expected failures without hiding defects — Declare expected failures, preserve their context, and recover by tag without turning crashes into successful outcomes.

  29. Run Effect at the integration boundary. Build the runtime where a calling framework enters, reuse its services, and dispose it when that integration ends.

    Replacing Effects with native Promises loses composition of typed failures and requirements.¶

  30. Schemas define the boundary. Define accepted data with Schema, decode unknown input before dispatch, and encode results through the declared contract.

    Report malformed input separately from an expected domain refusal.¶

  31. Scopes release resources when work ends. Acquire resources lazily, keep their use inside the owner, and release them after success, failure, or interruption.

    The test cases exercise success, expected failure, and interruption.

  32. ship. Learn how to ship a change through merge, CI, release, stage deployment, rollout, verification, rollback and flags.

    Effect: the library for describing work with typed failures and required services.¶

  33. Source change history (log.md). The generated change log as Markdown.

    Handle expected failures without hiding defects — edited: fix(lore): re-pin the CLI failure excerpt and link glossary first uses

  34. Structure an Effect codebase by domain. Start with folders for application work, services and Layers in the same file, and startup code that supplies implementations.

    See the error model.¶

  35. uncomplect. Find responsibilities that a rat-stack design combines, separate them into capabilities, cartridges, machines, features, and clients, and enforce that separation through types and checks. Use when asked to simplify, review, or replace a design, "what would Rich Hickey do", "optimize for deletion", or "define this error out of existence".
  36. Why TypeScript is a good fit for Scala developers. John De Goes and Michael Arnaldi discuss carrying functional programming ideas into TypeScript.

    Typed functional effects describe work with typed failures and dependencies.

Unlinked mentions (1)
  • Effect basics → It also turns the expected failure into a rejected Promise rather than preserving the Effect error channel for the caller.