03-error-handling
Effect-TS 4 error handling — Effect.catch, catchTag, catchTags, typed channels, and absorb patterns
- License 许可
- MIT
- 最近更新
- 2026-05-31
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- 03-error-handling
- license
- MIT
- description
- Effect-TS 4 error handling — Effect.catch, catchTag, catchTags, typed channels, and absorb patterns
- compatibility
- opencode
03 SKILL.md 正文
Error Handling Patterns
Define errors at the module boundary
import { Schema } from "effect";
// Serializable tagged error — primary pattern
export class ParseError extends Schema.TaggedErrorClass<ParseError>()("ParseError", {
input: Schema.String,
message: Schema.String,
}) {}
// With unknown cause
export class FetchError extends Schema.TaggedErrorClass<FetchError>()("FetchError", {
url: Schema.String,
cause: Schema.Defect,
}) {}
// Plain class — lightweight, non-serializable
export class LlmError {
readonly _tag = "LlmError";
constructor(readonly message: string) {}
}
catchTag / catchTags — targeted recovery
// Single tag
program.pipe(Effect.catchTag("ParseError", (e) => Effect.succeed(`fallback: ${e.message}`)));
// Multiple tags — same handler
program.pipe(Effect.catchTag(["ParseError", "NetworkError"], (_) => Effect.succeed(0)));
// Multiple tags — individual handlers
program.pipe(
Effect.catchTags({
ParseError: (e) => Effect.succeed(`parse: ${e.message}`),
NetworkError: (e) => Effect.succeed(`net: ${e.statusCode}`),
}),
);
Effect.catch — all typed errors
Effect.catchAll does not exist in Effect 4. Use Effect.catch.
It only catches recoverable (typed) errors — defects still propagate.
// ❌ Effect 3 — compile error in Effect 4
program.pipe(Effect.catchAll((e) => Effect.succeed("fallback")));
// ✅ Effect 4
program.pipe(Effect.catch((_e) => Effect.succeed("fallback")));
Absorb boundary — unknown errors into typed channel
When calling code that may fail with unknown (SDK errors, callbacks),
use Effect.catch to absorb into a safe fallback.
// LLM SDK may throw AiError or unknown — absorb at the boundary
const rawText =
yield *
LanguageModel.generateText({ prompt }).pipe(
Effect.map((r) => r.text),
Effect.catch((_e) => Effect.succeed(`@main = λf.λx.x // error: ${String(_e)}`)),
);
Wrapping at service boundaries
Map errors as they cross a layer boundary to keep the error type local.
const findById = Effect.fn("Repo.findById")(function* (id: string) {
return yield* sql`SELECT * FROM users WHERE id = ${id}`.pipe(
Effect.mapError((cause) => new UserRepoError({ cause })),
);
});
Reason errors — nested categorized sub-errors
export class AiError extends Schema.TaggedErrorClass<AiError>()(
"AiError",
{ reason: Schema.Union([RateLimitError, QuotaExceededError, SafetyBlockedError]) },
) {}
// Catch one reason
program.pipe(
Effect.catchReason("AiError", "RateLimitError",
(r) => Effect.succeed(`retry after ${r.retryAfter}s`),
),
)
// Unwrap into error channel
program.pipe(
Effect.unwrapReason("AiError"),
Effect.catchTags({
RateLimitError: (r) => ...,
QuotaExceededError:(r) => ...,
}),
)
Catching defects (unexpected failures)
import { Cause } from "effect";
program.pipe(
Effect.catchCause(
(cause) => (Cause.isFailure(cause) ? Effect.succeed("recovered") : Effect.failCause(cause)), // re-raise non-failure causes
),
);
Return before yield* error
export const load = Effect.fn("load")(function* (id: string) {
if (!id) return yield* new NotFoundError(); // return stops TS inference here
return yield* fetchById(id);
});
Never fail silently
// ❌ swallows the error
.pipe(Effect.catch((_) => Effect.succeed(undefined)))
// ✅ log then recover
.pipe(
Effect.catch((e) =>
Effect.gen(function* () {
yield* Effect.logError("unexpected error", e)
return defaultValue
}),
),
)
04 同仓库更多 Skills
tmux-workflow
Development workflow with tmux — run dev servers, Storybook, and background processes in persistent sessions with live logs, while keeping OpenCode free for chat
04-anti-patterns
React anti-patterns to avoid — manual JSX repetition, useEffect misuse, reference instability, prop drilling, conditional hooks, and common performance traps
03-state-management
React state management patterns — lifting state, colocation, URL state, server state with TanStack Query, local state with useState/useReducer
02-component-composition
React component composition patterns — render props, compound components, list rendering with map, slot patterns, and layout primitives
01-fp-style
React functional programming style — pure components, hooks conventions, Effect Atom integration, and Tailwind patterns
react-animation
React animation with react/motion (Framer Motion) — declarative animations, gestures, layout animations, and performance best practices