skills/fp-skills/skills/fp-error-handling/SKILL.md
Handle errors as values instead of throwing exceptions. Result/Either pattern, railway-oriented programming, and validation with error accumulation. Activate when: writing error handling, try/catch blocks, validation logic, operations that can fail, chaining fallible operations, form validation, API input validation, or when the user mentions Result, Either, error handling, or validation patterns. Works in any language (TypeScript, Python, Go, Rust, Java).
npx skillsauth add olion500/skills fp-error-handlingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Treat errors as data, not control flow. Functions that can fail return Result<Success, Error> instead of throwing.
Return success or error as a value. Type signature makes failure explicit.
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });
const err = <E>(error: E): Result<never, E> => ({ ok: false, error });
Other languages: Python Ok|Err dataclass union, Go val, err (already idiomatic), Rust Result<T,E> (built-in), Java sealed interface.
If any step fails, skip the rest. Errors flow along the "error rail."
Input → [validate] → [normalize] → [save] → Output
↓ ↓ ↓
Error ─────────────────────────→ Error
const andThen = <T, U, E>(
result: Result<T, E>,
fn: (value: T) => Result<U, E>
): Result<U, E> =>
result.ok ? fn(result.value) : result;
// Chain: stops at first failure
const processUser = (input: RawInput): Result<User, string> =>
andThen(andThen(validateEmail(input), normalizeUser), saveUser);
Don't stop at the first error. Show the user everything wrong at once.
const validateUser = (input: RawUser): Result<User, string[]> => {
const errors: string[] = [];
if (!input.email?.includes("@")) errors.push("Invalid email");
if (!input.name?.trim()) errors.push("Name required");
if (!input.age || input.age < 0) errors.push("Invalid age");
return errors.length === 0
? ok({ email: input.email, name: input.name.trim(), age: input.age })
: err(errors);
};
| What you're doing | Pattern | Why | |---|---|---| | Parse/validate a single value | Result | One thing can go wrong | | Chain dependent async operations (fetch → process → save) | Railway | Each step depends on previous | | Form/API input validation | Validation | User needs all errors at once | | Mixed: validate input then process | Validation first → Railway after | Validate all fields, then chain processing |
const tryCatch = <T>(fn: () => T): Result<T, Error> => {
try { return ok(fn()); }
catch (e) { return err(e instanceof Error ? e : new Error(String(e))); }
};
app.post("/users", (req, res) => {
const result = processUser(req.body);
if (result.ok) res.json(result.value);
else res.status(400).json({ errors: result.error });
});
Principle: Result lives inside your domain. Convert at boundaries (HTTP handlers, CLI output, third-party libraries).
Result<T, string> in production — use typed error unions: Result<User, "not_found" | "inactive" | "rate_limited">Result<Result<T, E1>, E2>) — use andThen/flatMap to flattenresult.value without checking result.ok, you've defeated the purpose?. or if sufficesval, err, Rust's Result)development
Search and query Elasticsearch/Kibana database models using curl API. Use for querying database models, searching Kibana indices, checking Elasticsearch data, investigating data in Kibana, finding records by ID, searching documents. Supports multiple environments (dev, qa, stage, production-us, production-au, production-eu).
development
Search and analyze Datadog logs and metrics using API for cupixworks-api and cupixworks-worker services. Use when debugging errors, investigating issues, searching logs, analyzing worker jobs, checking Sidekiq logs, querying metrics, or finding specific log entries by class/function names. Supports error/warn/info log levels with 14-day retention for logs.
tools
Create, update, search, transition, link, and read comments on Jira issues via CLI. MUST use this skill whenever the user pastes or mentions any atlassian.net URL (Jira issues, Confluence pages, focusedCommentId links, board links — anything from *.atlassian.net). Also use for: TSLA-* ticket references, JQL searches, issue status changes, reading comments, creating bugs, updating descriptions. This is the ONLY way to interact with Jira/Atlassian — there is no MCP Atlassian available.
development
Search Cupix Watch (Kibana/Elasticsearch) application logs at watch.cupix.com. Use when the user asks to search logs, find errors, debug processing issues, or investigate service behavior. Triggers on keywords like "log", "watch", "kibana", "error log", service names (skat, pano, api, worker, vista), or mentions of cupix processing pipelines.