Errors Deserve Better
OTA-299 timeout-after-capture benchmark: typed errors, explicit retry policy, and exhaustive UX mapping.
Here’s the thing about software: it fails. Not sometimes. Always.
The database takes a nap when you need it. The payment provider goes for coffee. The user types “banana” where you expected a number.
Most programmers treat errors like embarrassing relatives. They pretend they don’t exist until they show up and ruin everything. But what if we treated errors as first-class citizens?
| Safety Net (try/catch) | Railway (neverthrow) |
| Happy path first | Success track |
| Slip and fall | Switch point |
| Caught (maybe) | Error track |
| Control Room (Effect) | Orchestrator (awaitly) |
| Blueprint | Declare steps |
| Control panel | Auto-infer errors |
| Execute | Execute with step() |
| Platform (Vercel Workflow) | |
| “use step” directive | |
| Compiler transforms code | |
| Platform handles durability |
| Approach | Error Visibility | Composability | Ergonomics | Bundle Size |
|---|---|---|---|---|
| try/catch | Low (hidden) | Medium | High | Minimal |
| awaitly | High | High | High | Light |
| neverthrow | High | High | Medium | Light |
| Effect | Very High | Very High | Low → Medium | Heavy |
Whatever approach you choose, evaluate it against these benchmarks:
Need to handle errors? │ ▼ Simple use case? ──Yes──▶ try/catch │ No │ ▼Want compiler-verified error handling (Result types)? │ No ──▶ try/catch │ Yes │ ▼ Want async/await syntax? ──No──▶ neverthrow │ Yes │ ▼ Need full ecosystem (DI, layers, tracing)? │ Yes ──▶ Effect │ No ──▶ awaitlystep.all, step.map, step.race) without the Effect runtime.andThen())Errors Deserve Better
OTA-299 timeout-after-capture benchmark: typed errors, explicit retry policy, and exhaustive UX mapping.
vs Promises
Compare Promise + try/catch with AsyncResult. See why typed errors catch bugs at compile time.
vs try/catch
Compare traditional exception handling with Result types. See why explicit errors catch bugs at compile time.
vs neverthrow
Both use Result types. Compare chaining (.andThen()) vs async/await (step()).
vs Effect
Compare lightweight orchestration vs full ecosystem. Effect-style ergonomics with native async/await (step.all, step.map, step.race) and explicit DI.
Effect-style layers in awaitly
Effect-style dependency injection without Tags or Layers: pass deps at create time, pre-bind with provide(...), or override per run for tests.
vs Vercel Workflow
Compare compiler directives with explicit Result types. See when platform integration beats portability.
Errors aren’t bugs, they’re features. The difference between a junior and senior developer isn’t bug-free code. It’s designing around inevitable failure.
There’s no “correct” choice. Each approach is a tool:
But whatever you choose, choose deliberately. Your future self at 3 AM will thank you.