Skip to content

Repair

An answer that fails validation can be sent back to the model with the reason, a bounded number of times. Repair is neither of the two things products usually do here:

  • It is not coercion. Nothing fills a missing field with a default, drops a field to make an object fit, or casts a value into the declared type. An object the kit finished is an object the caller cannot attribute to anyone.
  • It is not a blind retry. The same prompt sent again is a second charge with no new information in it. The repair prompt names every failing path and what was wrong with each, taken from the validation error itself.

Asking for it

Agent(
    name="planner",
    instructions="Plan trips.",
    model="claude-sonnet-5",
    output_type=TripPlan,
    repair=RepairConfig(max_attempts=2),
)

Nothing is repaired by default: Agent.repair is None and the first violation is terminal. A high-stakes agent that wants that on the record writes repair=RepairConfig(enabled=False) rather than deleting the block, so the decision reads as a decision instead of an oversight.

What goes back

Only what failed, and the schema:

That answer did not validate against the schema. What failed:
- nights: Field required

Answer again with one JSON object and nothing else, correcting only what is
listed above and inventing nothing. It must validate against this JSON Schema:
{ ... }

The kit never supplies a value for the failing field. A prompt that says what the answer should be is coercion with extra steps, and the answer would be the kit's.

What it costs

A repair attempt is an ordinary model call: its tokens land on run.usage, it is recorded against the budget policy, and it is bounded by the run deadline and the iteration cap like any other. Repair cannot spend past a ceiling — a run whose budget will not pay for the next attempt ends budget_exhausted instead of making it.

What is recorded

Event When
schema_violation Every attempt that failed, including the ones that were repaired
repair_requested The failure was sent back. Names the type, the failing fields, and which attempt of how many
repair_abandoned The same failure came back after being told what it was
output_validated A later attempt validated

Repair rate per agent and prompt version is repair_requested over runs; the recovery rate is how many of those still reach completed.

When repair is futile

A model told exactly which field failed and answering with the identical failure is not going to converge — the declared constraint cannot be satisfied as instructed. Rather than spending the rest of the budget proving it, the run stops at that point, records repair_abandoned and fails with a configuration error naming the type. That is a defect in the declaration, not a bad day for the model.

Running out

Exhausting the budget fails the run. run.output is None, the last attempt's violation is on the run with its failing paths and schema hash, and no partial object is returned.