result-error-handling
A utility for implementing and managing error handling patterns in brepjs using Result types and custom error codes.
Install
mkdir -p .claude/skills/result-error-handling && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/17444" && unzip -o skill.zip -d .claude/skills/result-error-handling && rm skill.zipInstalls to .claude/skills/result-error-handling
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
This skill should be used when working with Result<T,E>, BrepError, or error paths in brepjs — deciding whether to throw or return a Result, constructing errors with codes, or handling failures. Trigger phrases include "should this throw or return err", "Called unwrap() on an Err", "add a new error code", "BrepErrorCode", "kernelCall", "unsupportedError", "BrepWrapperError", "the operation failed silently", "error was swallowed", "how do I unwrap this Result", or writing a new *Fns.ts function that can fail.Key capabilities
- →Return `Result<T, BrepError>` for expected failures in brepjs operations.
- →Throw `BrepBugError` for programmer bugs or broken invariants.
- →Throw `BrepWrapperError` when unwrapping an `Err` from the `shape()` facade.
- →Construct errors using `kernelCall` for kernel operations.
- →Manually construct `BrepError` objects with specific kinds and codes.
- →Translate cryptic OCCT messages into actionable text with `translateKernelError()`.
How it works
The skill guides the selection of failure channels, either returning a `Result` for expected failures or throwing an exception for programmer bugs. It provides helpers like `kernelCall` to construct errors with translated messages and suggestions.
Inputs & outputs
When to use result-error-handling
- →Deciding whether to throw or return an error
- →Constructing new error codes
- →Handling operation failures
- →Unwrapping result types
About this skill
Result types and error handling
Every fallible operation in brepjs returns Result<T, BrepError> instead of throwing. The type, all combinators, and the extraction helpers live in src/core/result.ts (zero internal imports — a pure foundation module). Error kinds, the code catalog, and per-kind constructors live in src/core/errors.ts.
The two failure channels
Pick the channel before writing any error-handling code:
| Situation | Channel | Mechanism |
|---|---|---|
| Expected failure (bad input, kernel op failed, unsupported capability, file won't parse) | Result | err(validationError(...)), kernelCall(...), etc. |
| Programmer bug / broken invariant ("this can never happen") | Throw | bug(location, message) from src/utils/bug.ts — throws BrepBugError, never meant to be caught |
Out-of-bounds index that is valid by construction (under noUncheckedIndexedAccess) | Throw | safeIndex(arr, i, context) in src/core/errors.ts — the sanctioned arr[i]! replacement |
| Cooperative cancellation | Throw | if (signal?.aborted) throw signal.reason (see src/topology/booleanFns.ts) |
The rule for Layers 2–3 (.claude/commands/new-operation.md, CLAUDE.md): never throw for expected failures — return ok(...) or err(...). No ESLint rule enforces this mechanically, so it must be applied by discipline in every new *Fns.ts function. The exceptions above (bug(), safeIndex(), abort rethrows) are the only tolerated throws.
The one sanctioned Result→throw boundary is the fluent shape() facade in src/topology/wrapperFns.ts: every chainable method funnels through an internal unwrapOrThrow that throws BrepWrapperError on Err. See "The throwing boundary" below.
Constructing errors
Prefer kernelCall for kernel operations
src/core/kernelCall.ts is the standard error-construction path in *Fns.ts files. It wraps try/catch, casts the result, translates cryptic OCCT messages, and auto-attaches a suggestion:
// src/topology/shapeFns.ts
return kernelCall(
() => getKernel().downcast(shape.wrapped),
BrepErrorCode.CLONE_FAILED,
'Failed to clone shape'
) as Result<T>;
Three variants:
| Helper | Returns | Use when |
|---|---|---|
kernelCall(fn, code, message, kind?) | Result<AnyShape> | Kernel call returns a KernelShape; auto-runs castShape() |
kernelCallRaw<T>(fn, code, message, kind?) | Result<T> | Kernel call returns anything else (string, number, array) |
kernelCallScoped(fn, code, message, kind?) | Result<AnyShape> | fn(scope) needs intermediate kernel allocations — the DisposalScope is disposed even on the error path (see the memory-and-disposal skill) |
On exception, the error message becomes `${message}: ${translated}` where translateKernelError() (src/core/kernelErrorTranslation.ts) maps ~12 cryptic OCCT patterns (BRepAlgoAPI failures, fillet radius too large, degenerate geometry, ...) into actionable text with the original appended as (kernel: ...). Translation applies only when kind is 'KERNEL_OPERATION' (the default). ERROR_CODE_SUGGESTIONS in the same file maps a dozen codes (FUSE_FAILED, CUT_FAILED, *_NOT_3D, SWEEP_FAILED, LOFT_FAILED, DRAFT_FAILED, ...) to suggestion strings that ride along automatically.
Manual construction: pick the kind-matching constructor
BrepError is a plain object: { kind, code, message, suggestion?, cause?, metadata? } (src/core/errors.ts). There are 9 kinds, each with a constructor sharing the signature (code, message, cause?, metadata?, suggestion?):
| Kind | Constructor | Use for |
|---|---|---|
VALIDATION | validationError | Bad input parameters (check these first, before touching the kernel) |
KERNEL_OPERATION | kernelError | Kernel op failed (prefer kernelCall unless building the error by hand) |
TYPE_CAST | typeCastError | Result was not the expected shape type (e.g. boolean returned non-3D) |
COMPUTATION | computationError | Geometric computation failed (intersection, skeleton, center of mass) |
IO | ioError | Import/export failure |
QUERY | queryError | Shape query failure (e.g. finder not unique) |
MODULE_INIT | moduleInitError | Initialisation failure |
UNSUPPORTED | unsupportedError | Capability not supported by the current kernel (ADR-0006) — see the kernel-abstraction skill |
SKETCHER_STATE | sketcherStateError | Currently unused in src; exists for sketcher state transitions |
Always thread context through:
cause: the original exception. Dropping it destroys kernel diagnostics.metadata: structured context. Real example fromsrc/topology/modifierFns.ts:
return err(
kernelError('FILLET_FAILED', `Fillet operation failed: ${raw}`, e, {
operation: 'fillet',
edgeCount: selectedCount,
radius,
})
);
suggestion: a recovery hint. Theshape()wrapper folds it into the thrown message ("...\nSuggestion: ..."), so it reaches users.
Error codes
BrepErrorCode (src/core/errors.ts) is an as const catalog of ~124 codes grouped by category, with a matching literal-union type. Use BrepErrorCode.X instead of a raw string whenever the code exists — but know two caveats:
BrepError.codeis typedstring, not the union — a raw-string typo compiles fine. The catalog is advisory; checking it is on the author.- The catalog is incomplete: dozens of codes exist in src only as raw string literals (
FILLET_FAILED,WIRE_NOT_CLOSED,THREAD_INVALID_PITCH, and whole families). Grep before assuming a code is new.
To add a new code:
- Add the constant to
BrepErrorCodeinsrc/core/errors.tsunder its category group (kernel-op, validation, IO, ...). - Use it via the kind-matching constructor, or pass it to
kernelCall. - Optionally add an entry to
ERROR_CODE_SUGGESTIONSinsrc/core/kernelErrorTranslation.tssokernelCallauto-attaches a recovery hint. - Optionally add a row to the tables in
docs/errors.md(hand-maintained, no CI check — see the staleness warning below).
Consuming Results
| Need | Use | Notes |
|---|---|---|
| Branch on outcome | isOk(r) / isErr(r) | Type guards; narrow to Ok<T> / Err<E> |
| Handle both arms as an expression | match(r, { ok: v => ..., err: e => ... }) | |
| Extract in a test or script | unwrap(r) | Throws with [kind] CODE: message formatting on Err |
| Extract with fallback | unwrapOr(r, default) / unwrapOrElse(r, fn) | Never use to paper over failures the caller should see |
| Chain fallible steps | andThen (alias flatMap), or pipeline(input).then(fn).then(fn).result | Both short-circuit on first Err |
| Transform value / error | map / mapErr / mapBoth | |
| Combine many | collect(results) (alias all), zip(a, b) | collect short-circuits on first Err; zip is re-exported from src/index.ts as zipResults |
| Side-effect without consuming | tap / tapErr | tapErr is the idiomatic "log and pass through" |
Content truncated.
When not to use it
- →When an operation fails silently without an error channel.
- →When bad geometry is produced with an `Ok` result.
- →When a plain `Error` is thrown from a `*Fns.ts` function.
Limitations
- →The rule to never throw for expected failures is enforced by discipline, not mechanically.
- →The `docs/errors.md` resource is partially stale and may not align with `src/core/errors.ts`.
- →The `withKernel(id, fn)` helper is sync-only and can lead to confusing errors in async code after an `await`.
How it compares
This workflow provides structured error handling with specific error types and translation, unlike a generic approach that might rely on untyped exceptions or silent failures.
Compared to similar skills
result-error-handling side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| result-error-handling (this skill) | 0 | 25d | Review | Intermediate |
| javascript-mastery | 7 | 6mo | No flags | Beginner |
| tech-debt-analyzer | 5 | 8mo | Review | Intermediate |
| error-handling | 2 | 2mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
javascript-mastery
davila7
Comprehensive JavaScript reference covering 33+ essential concepts every developer should know. From fundamentals like primitives and closures to advanced patterns like async/await and functional programming. Use when explaining JS concepts, debugging JavaScript issues, or teaching JavaScript fundamentals.
tech-debt-analyzer
ailabs-393
This skill should be used when analyzing technical debt in a codebase, documenting code quality issues, creating technical debt registers, or assessing code maintainability. Use this for identifying code smells, architectural issues, dependency problems, missing documentation, security vulnerabilities, and creating comprehensive technical debt documentation.
error-handling
EpicenterHQ
Error handling patterns using wellcrafted trySync and tryAsync. Use when writing error handling code, using try-catch blocks, or working with Result types and graceful error recovery.
codex-code-review
tyrchen
Perform comprehensive code reviews using OpenAI Codex CLI. This skill should be used when users request code reviews, want to analyze diffs/PRs, need security audits, performance analysis, or want automated code quality feedback. Supports reviewing staged changes, specific files, entire directories, or git diffs.
dead-code
parcadei
Find unused functions and dead code in the codebase
devtu-fix-tool
mims-harvard
Fix failing ToolUniverse tools by diagnosing test failures, identifying root causes, implementing fixes, and validating solutions. Use when ToolUniverse tools fail tests, return errors, have schema validation issues, or when asked to debug or fix tools in the ToolUniverse framework.