ContractResult<T> — a discriminated union on the ok field. Boundary never throws. You always get a structured result.
Success: result.ok === true
ok is true, data is fully typed from your Zod schema. It has passed schema validation and every rule. Safe to use directly in your application.
Failure: result.ok === false
ok is false, no data is returned to your application. The error object contains the full history of every attempt.
AttemptDetail
Each failed attempt records:ruleIssues is the typed companion to issues — same content, but with the rule’s name and fields attached so you can route, count, or trigger logic per-rule on the receiving side.
Pattern matching
Basic
Early return
Logging attempts
Handling permanent failure
WhenmaxAttempts is exhausted without an accepted output, you decide what happens next. The full attempt history is on result.error.attempts — use it to choose between retry-with-different-prompt, escalate-to-human, or fail-fast.
ruleIssues makes per-rule alerting cheap. Pair it with a metrics sink and you get a “which rule is degrading?” view with no extra plumbing.
Failure categories
Every failed attempt is classified:| Category | Meaning |
|---|---|
EMPTY_RESPONSE | Model returned nothing |
REFUSAL | Model refused the task |
NO_JSON | Response contained no JSON |
TRUNCATED | JSON was cut off or incomplete |
PARSE_ERROR | Malformed JSON |
VALIDATION_ERROR | Valid JSON but failed Zod schema |
RULE_ERROR | Passed schema but failed your rules |
RUN_ERROR | Your RunFn threw an error |
VALIDATION_ERROR means the structure was wrong. RULE_ERROR means the structure was right but the values were wrong — this is the gap Boundary exists to close.
Why not exceptions?
ContractResult<T> is the error handling path. No try/catch needed. If you want to throw:
Next steps
Guarantees
What Boundary promises when result.ok is true
When to Use
Where Boundary fits — and where it doesn’t