When schema validation fails, what should the repair turn send back to the model?
answer
- specificity of the error decides success
- name the path, the expectation, the actual value
- deterministic fixes before a model call
- truncation is not a repair case
- second attempts succeed far less often
basics
~20 sSend the exact validator error — the failing path, what was expected, what was received — together with the offending output and an instruction to return only the corrected object. Generic messages like "invalid output, try again" waste a full generation and rarely fix anything.
solid answer
~50 sA repair turn is only as good as the error signal it carries. The message should name the failing path, the expectation and the actual value verbatim: `commodity[2].hs_code: expected 6 digits, got "8471.30.01"` is actionable, while "your output was invalid" is not — the model has to guess what went wrong and often re-emits the same value. Include the prior output (or just the offending sub-object when the document is large), the constraint that failed, and a clear instruction to return the corrected object only. Two other disciplines matter. First, run **deterministic fixes before spending a model call**: strip code fences and surrounding prose, and coerce trivially-recoverable types. Second, **diagnose before repairing** — a response that failed because it was truncated at the token limit needs continuation or a larger limit, not a repair prompt, and a field that fails on a third of requests is a schema defect, not retry volume.
code
json · 4 lines{
"role": "user",
"content": "Validation failed on your previous output:\n- commodities[2].hs_code: expected 6 digits, got \"8471.30.01\"\n- incoterm: expected one of [EXW, FCA, FOB, CIF, DDP], got \"delivered duty paid\"\nReturn the corrected JSON object only, with no other text."
}go deeper
Know that when validation fails you can send the error back and ask for a correction, and that the message should say exactly which field failed and why rather than just "invalid".
Explain what belongs in the repair turn — path, constraint, actual value, prior output, format instruction — and why deterministic fixes like stripping code fences should happen in code before you pay for a generation.
Demonstrate diagnosis before looping: separate truncation from reasoning failures from schema defects, and act differently on each. Talk about keeping the repair turn small on large documents and lowering temperature for the correction attempt.
Frame repair rate as a product metric that should trend down. Own the decision of where effort goes — schema redesign, extraction decomposition, or better source preprocessing — versus absorbing failures in a loop that costs a generation on every affected request.
## The repair loop in one sentence Validate the model's structured output; if it fails, send the validator's own error back as a new turn and ask for a corrected object; validate again; cap the attempts. The loop is simple. Almost all of the engineering quality lives in what goes into that second message. ## Give the model a compiler error, not a build failure The single biggest determinant of repair success is error specificity. Compare two repair turns after a customs declaration fails validation: - `"Your output was invalid. Please try again following the schema."` - `"Validation failed: commodity[2].hs_code: expected 6 digits, got \"8471.30.01\". Return the corrected object only." The first tells the model nothing it did not already believe — it thought the output was fine. It will typically resample something close to the original and fail identically, having cost a full generation. The second names the location, the constraint and the actual value, which is enough to make the correction mechanical: strip the separators, keep six digits. So the repair message should carry, at minimum: the **path** to the failing field in a form that matches the document's structure, the **constraint** that was violated stated in plain terms, the **actual value** verbatim, and an explicit instruction about the expected response format. If several fields failed, list them all — models fix them in one pass, and one turn is cheaper than three. ## Send the offending output, but not necessarily all of it The model needs to see what it produced to correct it. For small documents, include the whole prior output. For large ones — a declaration with fifty commodity lines — sending the whole thing back on every attempt inflates cost and buries the error. A better pattern is to send the failing sub-object plus its path and ask for a replacement for that node only, splicing the result back in yourself. This keeps the repair turn small, keeps attention on the defect, and avoids the model rewriting fields that were already correct. Avoid letting the conversation accumulate. A repair loop that appends every failed attempt to a growing history pays for all of it on every subsequent turn and gives the model several wrong examples of its own output to anchor on. Constructing each repair turn freshly — original instruction, the (sub-)output, the error — is usually both cheaper and more accurate. ## Fix deterministically before you pay for a generation A surprising share of validation failures are mechanically repairable in code, and doing so is thousands of times cheaper than a model call: - Output wrapped in code fences or preceded by an explanatory sentence — extract the JSON span. - A number rendered as a numeric string, or a boolean as `"true"` — coerce where the target type is unambiguous. - Trailing commas or single quotes from a model in a permissive mood — a lenient parse pass. - Whitespace, casing or separator drift on a value whose canonical form is unambiguous. The rule of thumb: if a deterministic transformation cannot possibly change meaning, do it in code. Reserve model calls for failures that require judgment — a missing field, a wrong classification, a value that must be re-derived from the source. ## Diagnose the failure class before looping Not every validation failure is a repair candidate, and treating them uniformly is a classic mistake. - **Truncation.** If the response ended at the token limit, the object is incomplete through no fault of reasoning. The fix is a larger output allowance, a continuation, or a decomposed extraction — a repair prompt will just produce another truncated object. - **Schema defect.** If one field fails on a large fraction of requests, the loop is masking a design problem. Fix the schema — add an enum, clarify the format in the description, flatten the structure — and the repair traffic disappears from every future request. - **Source ambiguity.** If the model cannot fill a field because the source document genuinely does not contain it, no number of repair turns will conjure it. The right outcome is a null with a reason, or a human escalation — not a loop that eventually produces a plausible fabrication. ## Settings and expectations for the repair attempt Lower the sampling temperature for the repair turn: you want the model's most likely correction, not exploration. Keep the instruction narrow — "return only the corrected JSON object" — because a repair turn is an unusually strong invitation to add explanatory prose. And validate the repaired output with exactly the same validator; a repair that is accepted by a looser check defeats the whole arrangement. ## Know the shape of the success curve First-attempt repairs succeed at a high rate when the error message is specific, because most failures are small format slips. The second attempt succeeds far less often, because a failure that survived a precise error message is usually not a format slip at all — it is ambiguity, a missing fact, or a schema the model cannot satisfy. That curve is why repair budgets are small, and why the interesting design question is not how to retry harder but what to do when the budget runs out.
- Your repair loop has a 92% first-attempt success rate but only 30% on the second. What does that tell you?That the two attempts are failing for different reasons. The first attempt mops up format slips, which a precise error message fixes almost mechanically. Anything that survives that message is usually not a format problem — it is source ambiguity, a fact the document does not contain, or a schema the model cannot satisfy as written. The right response is to cap the budget at two, route the remainder to a human or a partial-record path, and mine those cases for schema defects rather than adding a third attempt.
- How do you keep a repair loop from being exploited by hostile content in the source document?Treat the model's output and the source document as untrusted data throughout. The repair turn should carry the validator's error, which is generated by your code, not by the model — never echo model-authored prose back as an instruction. Validation itself is a pure code path, so injected text cannot relax it. And the fact that an object finally validates says nothing about whether its values are legitimate: business rules, authorization checks and reference-data lookups still apply to the repaired result exactly as they would to a first-pass one.
- Would you send the whole failed document back, or only the failing part?It depends on size and coupling. For a small object, send the whole thing — it is cheap and gives full context. For a large document with one bad node, send the failing sub-object with its path and ask for a replacement for that node, then splice it back yourself. That keeps the turn small, focuses attention on the defect, and stops the model from rewriting fields that were already correct. The exception is when the error is a cross-field inconsistency, where the model genuinely needs both fields to reconcile them.
A good repair turn is a compiler error pointing at line 42 with the expected type; a bad one is a build log that only says FAILED.
saying these in an interview costs you the question
- Sends a generic "invalid output, try again" as the repair message
- Spends a model call on failures a deterministic fix would solve
- Retries a truncated response instead of raising the output limit
- Accumulates every failed attempt into a growing conversation
- Treats a field failing on a third of requests as normal retry volume