What you will be able to do
- Tell apart the schema syntax errors that structured outputs remove and the semantic errors your own validator still has to catch
- Write a retry that sends specific validation errors back to Claude instead of just running the same prompt again
- Put together a follow-up request that includes the original document, the failed extraction, and the validation errors
- Design extraction fields that expose discrepancies: a stated_total next to a calculated_total, and a conflict_detected boolean for source data that contradicts itself
Key concept
Retries are for semantic errors that the document can fix — Constrained decoding already guarantees that the output has the right shape. So a retry loop is only for meaning-level errors, like wrong sums or values in the wrong place, and only when the correct answer is actually in the source the model can see.
1.Schema syntax errors vs semantic validation errors
Before you design a retry loop, work out which failures actually need one. The structured outputs documentation lists what goes wrong when nothing constrains the output: parsing errors from invalid JSON, missing required fields, inconsistent data types, and schema violations that need error handling and retries. Its summary is blunt: without structured outputs, Claude can produce malformed JSON or invalid tool inputs that break your application.
There are two features that remove this whole category. JSON outputs (output_config.format) and strict tool use (strict: true) both use constrained decoding, so the model can only produce tokens that are valid under the schema. The strict tool use page says what that means for your code: functions get correctly typed arguments every time, and there is no need to validate and retry tool calls.
This is where people go wrong. Constrained decoding guarantees shape, not meaning. A schema can require stated_total to be a number. It can't require that number to equal the sum of the line items. A schema with both a patient and a guardian object can be satisfied by a date of birth placed under the wrong one, as long as both objects allow that field. These are semantic validation errors: the output parses, the types are right, and it's still wrong. Only your own validation logic catches them, and they're what a retry loop is for.
| Failure | Example | Removed by structured outputs / strict tool use? | What catches it |
|---|---|---|---|
| Invalid JSON syntax | JSON.parse() throws | Yes | Constrained decoding |
| Missing required field | Required key left out | Yes | Constrained decoding |
| Wrong data type | passengers sent as a string instead of an integer | Yes | Constrained decoding |
| Values don't add up | Line items don't sum to the stated total | No | Your semantic validator, then a retry with feedback |
| Value in the wrong field | Patient data nested under a schema-valid but wrong object | No | Your semantic validator, then a retry with feedback |
Checkpoint 1 of 7· Check yourself
A team turns on structured outputs for receipt extraction and then removes all of its post-extraction validation, reasoning that the schema is now guaranteed. Which problem will now get through unnoticed?
The guarantee covers schema violations only: syntax, types, and required fields. A value that has the right type but is arithmetically inconsistent satisfies the schema, so only a semantic check catches it.
“Structured outputs guarantee schema-compliant responses through constrained decoding”Source: platform.claude.com
2.Retry with specific error feedback
Once your validator finds a semantic error, the weakest response is to send the identical request again and hope for a different result. Nothing in that request tells the model what it got wrong. The better pattern is the one the tool-use tutorial teaches for failing tools: send the error back instead of crashing, with is_error: true on the tool result. In the tutorial's words, Claude reads the error and can retry with corrected input, ask for clarification, or explain the limitation.
The content moderation cookbook shows this as an extraction-quality loop. A static validator checks Claude's compiled rules, and any problems it finds (an invented field, an enum value outside its allowed set) go back to Claude as a fix-only turn. The cookbook says these exact messages go back to Claude to fix. Look at how much one of them tells the model:
"bad2": [
"bad2.when: 'liquor' not in enum for 'ad_category': ['alcohol', 'gambling', 'financial_services', 'pharma_supplements', 'weight_loss', 'cosmetics_skincare', 'apparel_footwear', 'electronics', 'food_beverage', 'other']"
],A message like "extraction invalid" leaves the model guessing. This one says where the problem is (bad2.when), what was wrong ('liquor'), and what would be accepted. The evaluator-optimizer pattern explains why this works: a feedback loop fits when LLM responses can be measurably improved by feedback and the evaluation criteria are clear. The cookbook's guidance on writing feedback also fits validation errors: ask for a one-line scoreboard, then one bullet per failure saying what's wrong and what to do. In an extraction pipeline, that means each failed check becomes one line naming the field path, the problem, and the expected relationship, such as "line_items sum to 1,150 but stated_total is 1,200".
Checkpoint 2 of 7· Exam question
A reimbursement pipeline extracts a required "project_code" field from scanned expense reports. On one submission, the employee left the project code blank on the physical form, so it does not appear anywhere in the scanned image. After three retries with error feedback, the field is still empty. What should the pipeline do next?
Correct answer: A — Stop retrying and route the record to a human, since the code is genuinely absent from the source rather than a structural failure
- A. Correct. Retries only help when the failure is a format or structural mismatch; when the information simply is not present in the source, no amount of retrying can recover it, so the correct action is to stop and escalate for human resolution.
- B. Incorrect. The failure is not a schema or instruction-clarity problem, so further schema-focused instructions cannot surface data that was never captured on the form.
- C. Incorrect. Raising temperature increases output variance but does not create information that does not exist in the source document; it may even introduce a fabricated value.
- D. Incorrect. A more capable model still cannot extract a value that is absent from its input; model capability does not substitute for missing source data.
Checkpoint 3 of 7· Check yourself
A semantic validator flags an extracted record. Which retry message gives Claude the best chance of fixing it?
The repair loop works because the validator's own specific messages go back to the model, so it knows exactly what to change. A generic retry gives it nothing new to act on.
“In a live compile these exact messages go back to Claude to fix.”Source: platform.claude.com
3.Building the self-correction follow-up request
A retry is a new API call, and the Messages API keeps no memory between calls. The documentation says it directly: the API is stateless, so you always send the full conversation history. If your follow-up contains only the error message, Claude has nothing to fix. If it contains only the failed JSON and the error, Claude can rearrange keys but can't check the values against anything.
A follow-up that leads to real self-correction contains three things:
1. The original document, with the original extraction instructions. Without the source, the model can only shuffle what it already produced. With it, the model can re-read the form and confirm each value. 2. The failed extraction, as an assistant turn. The docs say earlier turns don't have to come from Claude and that you can use synthetic assistant messages. So you can rebuild the conversation as if the failed output had just been produced, even in a fresh request. 3. The specific validation errors, in a final user turn that asks for a complete corrected extraction checked against the document.
The hallucination guide calls this iterative refinement: using Claude's outputs as inputs for follow-up prompts, asking it to verify or expand on what it said before. The multi-turn sample below has exactly this structure: user, assistant, user.
Checkpoint 4 of 7· Fill the gap
In a follow-up request, the failed extraction goes in as an earlier turn. Which role completes this multi-turn sample?
message = anthropic.Anthropic().messages.create(
model="claude-opus-5-5",
max_tokens=1024,
messages=[
{"role": "user", "content": "Hello, Claude"},
{"role": " ? ", "content": "Hello!"},
{"role": "user", "content": "Can you describe LLMs to me?"},
],
)
print(message)The model's earlier reply, or in a retry the failed extraction, goes in an assistant turn between the two user turns. The docs note that this turn can be synthetic.
Source: platform.claude.comCheckpoint 5 of 7· Exam question
A security review assistant extracts structured findings from source code and developers frequently dismiss a large share of the findings tied to one particular helper function used for input sanitization. The team wants to analyze this dismissal trend systematically over time. What should be added to the structured finding schema to support this analysis?
Correct answer: A — A detected_pattern field naming the specific construct that triggered the finding, so dismissals can be grouped by construct
- A. Correct. Recording the specific triggering construct in a detected_pattern field lets the team aggregate dismissals by pattern, revealing which constructs generate disproportionate false positives so the detection logic can be tuned.
- B. Incorrect. Unstructured free text cannot be reliably aggregated or queried at scale, making systematic trend analysis across many findings impractical.
- C. Incorrect. A confidence score without a reference to the triggering construct does not let analysts isolate which specific pattern is responsible for the dismissals.
- D. Incorrect. Raising severity indiscriminately does not help identify which construct is generating false positives and would increase noise rather than support the requested analysis.
Checkpoint 6 of 7· Put it in order
Put the turns of a stateless self-correction request in order
- 1.User turn: the specific validation errors and a request for a complete corrected extraction checked against the document
- 2.Assistant turn: the failed extraction exactly as it was produced
- 3.User turn: extraction instructions plus the full original document
Because the API is stateless, the request has to rebuild the whole exchange: the source and task first, then what the model produced, then the feedback on it.
“The Messages API is stateless, which means that you always send the full conversational history to the API.”Source: platform.claude.com
4.Self-correction fields: calculated_total and conflict_detected
A validator can only compare what it can see, so design the schema to expose the comparison. Instead of a single total, extract two fields: stated_total, the figure the document prints, and calculated_total, the figure the model computes from the line items it extracted. Your code then compares the two. A mismatch is a precise, checkable semantic error, and it becomes a one-line retry message such as "calculated_total is 1,150 but stated_total is 1,200". The model can re-read the source and fix a misread digit or a missed line item. This is the kind of document-versus-data check the cookbooks describe for invoice processing: extract data from documents, then flag discrepancies.
Sometimes the document itself is the problem. The printed total really doesn't match its own line items, or two sections of the source give different values. No retry can fix that, because every correct re-reading produces the same disagreement. For this case add a conflict_detected boolean. When the source is internally inconsistent, the model sets it to true and reports both values instead of silently picking one. The pipeline then routes the record to human review rather than looping. This follows the same logic as the limit of retry: a retry helps only when the right answer is in the document. It also follows the guidance to give Claude permission to admit uncertainty, and to make a field optional when the source may not contain what the schema asks for.
In short, calculated_total next to stated_total turns a hidden semantic error into a flagged discrepancy, and conflict_detected separates an extraction mistake, which a retry can correct, from a contradiction in the source, which needs a person.
Checkpoint 7 of 7· Check yourself
An invoice's printed line items sum to 1,150, but its printed total is 1,200 and nothing in the document explains the gap. The extraction has stated_total 1,200 and calculated_total 1,150. What should the pipeline do?
If the source contradicts itself, re-reading it gives the same disagreement, so a retry can't produce the right answer. Flagging the conflict and reporting both values lets a person resolve it.
“Explicitly give Claude permission to admit uncertainty.”Source: platform.claude.com
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Once strict tool use or structured outputs is on, extraction output no longer needs to be validated.Why is that wrong?
The guarantee covers schema compliance: syntax, types, and required fields. Values that don't add up, or that sit in the wrong schema-valid object, still pass and need a semantic validator.
Covered in Schema syntax errors vs semantic validation errors
2.A retry only needs the validation error, because the model remembers the document from the first call.Why is that wrong?
The API is stateless. Each follow-up has to resend the original document and the failed extraction along with the errors, or the model has nothing to check its correction against.
3.When calculated_total and stated_total disagree, keep retrying until they match.Why is that wrong?
A retry helps only when the correct answer is in the document. If the source contradicts itself, set conflict_detected and escalate instead of looping.
Covered in Self-correction fields: calculated_total and conflict_detected
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“Without structured outputs, Claude can generate malformed JSON responses or invalid tool inputs that break your applications.”
↩︎ Schema syntax errors vs semantic validation errors“Reliable: No retries needed for schema violations”
↩︎ Key concept“Structured outputs guarantee schema-compliant responses through constrained decoding”
↩︎ Exam trap 1“Reliable: No retries needed for schema violations”
↩︎ Prediction“Structured outputs guarantee schema-compliant responses through constrained decoding”
↩︎ Checkpoint - 2.
“No need to validate and retry tool calls”
↩︎ Schema syntax errors vs semantic validation errors - 3.
“Claude reads the error and can retry with corrected input, ask the user for clarification, or explain the limitation.”
↩︎ Retry with specific error feedback“send the error message back with is_error: true instead of crashing”
↩︎ Retry with specific error feedback - 4.
“go back to Claude as a fix-only turn”
↩︎ Retry with specific error feedback“In a live compile these exact messages go back to Claude to fix.”
↩︎ Checkpoint - 5.
“LLM responses can be demonstrably improved when feedback is provided”
↩︎ Retry with specific error feedback - 6.
“Ask for a one-line scoreboard, then one bullet per failure”
↩︎ Retry with specific error feedback - 7.
“The Messages API is stateless, which means that you always send the full conversational history to the API.”
↩︎ Building the self-correction follow-up request“You can use synthetic assistant messages.”
↩︎ Building the self-correction follow-up request“The Messages API is stateless, which means that you always send the full conversational history to the API.”
↩︎ Exam trap 2 - 8.https://platform.claude.com/docs/en/test-and-evaluate/strengthen-guardrails/reduce-hallucinationsOfficial docs
“asking it to verify or expand on previous statements. This can catch and correct inconsistencies.”
↩︎ Building the self-correction follow-up request“Explicitly give Claude permission to admit uncertainty.”
↩︎ Self-correction fields: calculated_total and conflict_detected“Explicitly give Claude permission to admit uncertainty.”
↩︎ Exam trap 3 - 9.
“If the task might not have all the information your schema requires, make those fields optional.”
↩︎ Self-correction fields: calculated_total and conflict_detected - 10.
“Extract data from documents, validate against purchase orders, flag discrepancies”
↩︎ Self-correction fields: calculated_total and conflict_detected