Skip to main content
When an LLM output fails validation, Boundary doesn’t just retry blindly. It extracts the specific violations, classifies the failure, and sends targeted repair instructions back to the model.

How it works

This is not blind retry. Each repair message is targeted to the specific failure. The model knows exactly what went wrong and what to fix.

The attempt.repairs field

Inside your RunFn, attempt.repairs is an array of plain { role, content } JSON objects. Most chat-style providers accept this shape directly or with a small mapping step.
On a retry, attempt.repairs looks like this:
Repair messages are always role: "user" — they carry the failure text from your rule’s check (or the schema/parse error) so the model sees exactly what to fix on the next attempt.
On the first attempt, repairs is empty. On subsequent attempts, it contains the failure messages from the previous attempt — one entry per rule or schema violation that fired.

Retry configuration

By default, Boundary retries up to 3 attempts with no delay between them.

Failure categories

Every failed attempt is classified into one of 8 categories. Each category has a default repair strategy:

Custom repair overrides

You can override or disable repair for specific categories:
Setting a category to false stops retrying for that failure type. Providing a function lets you craft custom repair messages.

When repair fails

If maxAttempts is exhausted without a valid output, the contract returns { ok: false, error }. The full per-attempt history is on error.attempts — including the failure category, the raw model output, and the typed ruleIssues on RULE_ERROR attempts.
Rejected data stays out of the success path. The contract never returns a partial or “best-effort” success value — either every rule passes or you get the structured error. If a particular contract is hitting maxAttempts regularly, that’s a signal: the rule may be too strict, the prompt may be missing context, or the model may be wrong for the job. Local logs can show this while you build; the hosted SDK can aggregate it across production traffic. See Results for handling patterns.

Next steps

Results

The ContractResult type

Guarantees

What Boundary promises

Observability

Start with local development logging to see repairs and failed attempts in your console. Add production observability when you need aggregate retry and rule-failure trends across real traffic.