From effect-ts
This skill should be used when the user asks about "Effect errors", "typed errors", "error handling", "Effect.catchAll", "Effect.catchTag", "Effect.mapError", "Effect.orElse", "error accumulation", "defects vs errors", "expected errors", "unexpected errors", "sandboxing", "retrying", "timeout", "Effect.cause", "TaggedError", "Schema.TaggedError", or needs to understand how Effect handles failures in the error channel.
npx claudepluginhub andrueandersoncs/claude-skill-effect-ts --plugin effect-tsThis skill uses the workspace's default tool permissions.
Effect distinguishes between two types of failures:
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Effect distinguishes between two types of failures:
Error type parameter, tracked at compile timeEffect<Success, Error, Requirements>;
// ^^^^^ Expected errors live here
import { Schema, Effect } from "effect";
class UserNotFound extends Schema.TaggedError<UserNotFound>()("UserNotFound", { userId: Schema.String }) {}
// Note: Schema.Unknown is semantically correct here because `cause` captures
// arbitrary caught exceptions whose type is genuinely unknown at the domain level.
// This is NOT type weakening - JavaScript exceptions can be any value.
class NetworkError extends Schema.TaggedError<NetworkError>()("NetworkError", { cause: Schema.Unknown }) {}
const getUser = (id: string): Effect.Effect<User, UserNotFound | NetworkError> =>
Effect.gen(function* () {
// ...implementation
return yield* Effect.fail(new UserNotFound({ userId: id }));
});
const divide = (a: number, b: number) => (b === 0 ? Effect.fail(new DivisionByZero()) : Effect.succeed(a / b));
program.pipe(Effect.catchAll((error) => Effect.succeed("fallback value")));
const program = getUser(id).pipe(
Effect.catchTag("UserNotFound", (error) => Effect.succeed(defaultUser)),
Effect.catchTag("NetworkError", (error) => Effect.retry(Schedule.exponential("1 second"))),
);
const program = getUser(id).pipe(
Effect.catchTags({
UserNotFound: (error) => Effect.succeed(defaultUser),
NetworkError: (error) => Effect.fail(new ServiceUnavailable()),
}),
);
const primary = fetchFromPrimary();
const fallback = fetchFromBackup();
const resilient = primary.pipe(Effect.orElse(() => fallback));
const program = fetchConfig().pipe(Effect.orElseSucceed(() => defaultConfig));
const program = rawApiCall().pipe(Effect.mapError((error) => new ApiError({ cause: error })));
const program = effect.pipe(
Effect.mapBoth({
onError: (e) => new WrappedError({ cause: e }),
onSuccess: (a) => a.toUpperCase(),
}),
);
When running multiple effects, collect all errors instead of failing fast:
const results = yield * Effect.all([effect1, effect2, effect3], { mode: "either" });
const [failures, successes] = yield * Effect.partition(items, (item) => processItem(item));
const result = yield * Effect.validate([check1, check2, check3], { concurrency: "unbounded" });
Defects are bugs/unexpected failures not tracked in types:
const defect = Effect.die(new Error("Unexpected!"));
const program = effect.pipe(Effect.orDie);
const sandboxed = Effect.sandbox(program);
The Cause type contains complete failure information:
import { Cause, Match } from "effect";
// In sandbox, you get full Cause - use Match for handling
const handled = Effect.sandbox(program).pipe(
Effect.catchAll((cause) =>
Match.value(cause).pipe(
Match.when(Cause.isFailure, () => {
// Expected error
return Effect.succeed(fallback);
}),
Match.when(Cause.isDie, () => {
// Defect - log and recover
return Effect.succeed(fallback);
}),
Match.when(Cause.isInterrupt, () => {
// Interruption
return Effect.succeed(fallback);
}),
Match.orElse(() => Effect.succeed(fallback)),
),
),
);
import { Schedule } from "effect";
const resilient = effect.pipe(
Effect.retry(Schedule.exponential("100 millis").pipe(Schedule.jittered, Schedule.compose(Schedule.recurs(5)))),
);
// Retry with condition - use Match.tag for error type checking
const conditional = effect.pipe(
Effect.retry({
schedule: Schedule.recurs(3),
while: (error) =>
Match.value(error).pipe(
Match.tag("NetworkError", () => true),
Match.orElse(() => false),
),
}),
);
const withTimeout = effect.pipe(Effect.timeout("5 seconds"));
const failOnTimeout = effect.pipe(
Effect.timeoutFail({
duration: "5 seconds",
onTimeout: () => new TimeoutError(),
}),
);
const result =
yield *
effect.pipe(
Effect.match({
onFailure: (error) => `Failed: ${error.message}`,
onSuccess: (value) => `Success: ${value}`,
}),
);
const result =
yield *
effect.pipe(
Effect.matchEffect({
onFailure: (error) => logError(error).pipe(Effect.as("failed")),
onSuccess: (value) => logSuccess(value).pipe(Effect.as("success")),
}),
);
catchTag pattern matchingcause field on error types is the canonical example (caught JS exceptions can be any value). Never use Schema.Unknown or Schema.Any for fields whose shape you can describe - define proper schemas instead.For comprehensive error management documentation, consult ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt.
Search for these sections: