LLM Output Validation and Repair: Making Structured Responses Safe to Use
You asked the model for JSON. You defined the schema, listed the required fields, and specified the exact types. The response came back wrapped in markdown…

Key topics
You asked the model for JSON. You defined the schema, listed the required fields, and specified the exact types. The response came back wrapped in markdown fences with a cheerful "Here is the JSON you requested:" before it. Or worse: the JSON parsed fine, but the status field contains a value your business logic has never seen before.
This is the moment where a lot of beginners discover the hard truth: a model that can follow a schema is not the same as a system that guarantees one. The model produces a draft. Your application owns the contract.
Why a Schema Is a Promise, Not a Guarantee
Even with a well-designed structured-output request, LLMs return malformed, wrapped, or incomplete JSON often enough that you need a plan. The model generates text that resembles JSON. It does not execute a contract. There is no compiler checking types, no runtime enforcing required fields, no linker complaining about missing references. There is only a probability distribution choosing the next token, and sometimes the next token is a backtick.
The useful reframe: treat every model response as untrusted input, the same way you would treat data arriving from an external API you do not control. You would never pipe raw third-party API responses straight into your database without checking them. LLM output deserves the same suspicion.
Validation is the layer that converts a draft into data your downstream code can trust. It sits between the model and everything else—your database, your UI, your business logic, your customers.
When you validate LLM output, you are really guarding against three families of failure:
- Invalid structure — the output is not parseable JSON, or it is missing required fields, or fields have the wrong types.
- Incomplete or wrong content — the JSON is well-formed, but a value is missing, empty, or contradicts your business rules.
- Unsafe or out-of-contract values — the output contains something that should never reach your system, like a banned category, an out-of-range number, or content that violates your policies.
Most beginners handle the first family and stop. The dangerous failures live in the second and third.
Knowledge check
Check your understanding
Answer this question before you continue.
The Validation Loop: Parse, Check, Decide
Think of validation as a loop with distinct stages, not a single check you bolt onto the end of a request. Each stage catches a different kind of failure, and each exit path handles it differently.
Step 1: Generate. The model returns its raw text response.
Step 2: Parse. This is the first gate. Strip any wrappers—markdown fences, explanatory text, leading or trailing prose—and extract the JSON payload. If you cannot extract parseable JSON at all, you already know the output needs repair or a retry.
Step 3: Validate structure. Check the shape against your schema. Are all required fields present? Do the types match? Is age an integer and not a string? Does the rating fall within the allowed range? Schema validation tools like Pydantic or Zod handle this cleanly, and they give you precise error messages you can feed back into the next step.
Step 4: Validate content. This is the semantic check, and it is where beginners most often drop the ball. The JSON is perfectly well-formed. The types are correct. But the category field contains a value your system has never heard of, or the confidence score is 0.97 when your business rules cap it at 0.95, or the extracted summary contains a banned phrase. Schema validation cannot catch these. Only content rules can.
Step 5: Decide. Route the output down one of three paths: accept, repair, or reject.
Model output → Parse → Schema check → Content check → Accept
↓ ↓
Repair? Retry?
↓ ↓
Reject ← ← ← ← ← ←
The loop is the mental model worth keeping. Each failure mode points to a specific stage, and each stage has its own remedy.
Knowledge check
Check your understanding
Answer this question before you continue.
Repair vs. Retry vs. Reject: Choosing the Exit Path
When validation fails, you have three options. Choosing well depends on understanding what each path costs and when it can be trusted.
Repair is cheap and deterministic. You fix trivial issues without asking the model anything: strip a stray markdown fence, remove a trailing comma, coerce a type you know is safe. If the model wrapped its JSON in ```json fences, your parser should handle that silently. If a number arrived as a string and your schema says the field is an integer, a safe coercion fixes it. Repair works when the problem is noise around the signal, not a problem with the signal itself.
Retry sends the error back to the model with context. This is the retry-with-feedback pattern: instead of just asking again, you tell the model what went wrong. "Your response was missing the customer_id field. Please provide a complete response that includes all required fields." The validation error becomes part of the next request, giving the model something concrete to correct. Retry works well for missing fields, wrong values the model can fix, and structural mistakes it can avoid on a second pass.
Reject is for cases where repair and retry cannot be trusted. Unsafe content, out-of-contract values, or repeated failures past your retry budget all deserve rejection. If the model returns a category that violates your policies, you do not want to retry until it guesses correctly—you want to refuse the result entirely and route it to a human or a fallback process.
Set a retry budget. Two or three attempts is usually enough. An unbounded loop does not solve the underlying problem; it just hides it behind repeated API calls and growing latency.
My rule of thumb: repair structural noise, retry content gaps, reject anything unsafe or persistently invalid.
Knowledge check
Check your understanding
Answer this question before you continue.
Deterministic Checks vs. LLM Judges
Validation tools come in two flavors, and they are not interchangeable.
Deterministic checks are fast, explainable, and repeatable. Schema validation, banned-value lists, range checks, format checks—these run in milliseconds, cost nothing beyond compute, and produce the same answer every time. When a rule is critical, a deterministic check should enforce it.
LLM judges can catch semantic problems that deterministic rules miss. Is this summary factually consistent with the source document? Does this classification match the intent of the request? These judgments require understanding, and deterministic rules struggle with them.
But here is the uncomfortable truth: an LLM judge inherits the very unreliability it is checking. The model evaluating your output can drift, disagree with human judgment, or produce confident but wrong assessments. This is the "who validates the validators" problem, and it is real. Research on LLM-assisted evaluation has documented criteria drift—where the standards themselves shift as the evaluator observes more outputs—and the general difficulty of aligning model judgment with human preferences.
The practical rule: use deterministic checks for anything critical, and treat an LLM judge as a supporting signal, never the sole gate. If a simple rule can enforce a constraint, do not delegate that constraint to a model. Save LLM judgment for the genuinely semantic questions that rules cannot answer, and even then, sample and verify its assessments against human judgment before you trust it at scale.
Knowledge check
Check your understanding
Answer this question before you continue.
Common Failure Modes and What They Teach
Real failures are the best teachers. Here are the patterns you will actually see, and what each one tells you about your loop.
Wrapped output. The model adds markdown fences or explanatory text around the JSON. Your parser must strip it before validation. This is a repair problem, and it is almost always solvable deterministically.
Missing required fields. The schema validation catches it, and retry-with-feedback usually resolves it. The model omitted customer_id because it did not have one to include—telling it the field is required gives it the chance to ask or to mark it as unknown.
Wrong but well-formed values. The model returns valid JSON with a value that violates your business rules. The priority field contains "urgent" when your system only accepts "low", "medium", or "high". Only content validation catches this. Schema validation passed; the semantic check failed.
Type drift. A number arrives as a string, or an enum arrives as free text. Schema constraints catch this, and a safe coercion can often repair it. But be careful: if the type drift signals a deeper misunderstanding, retry may be the better path.
Each failure mode points to a specific stage in the loop. That is why the loop is the mental model worth keeping—it tells you where to look when something breaks.
When Validation Is Not Enough
Validation has honest boundaries, and you should know them before you need them.
Validation confirms that output matches your contract. It does not prove the output is factually correct, well-written, or good for the task. A response can be perfectly valid JSON and completely wrong. Factuality and quality are evaluation problems, not validation problems. Evaluation asks whether the whole system meets the task; validation protects each individual output from breaking downstream code. They are complementary, and you need both.
Validation also adds latency and cost. Every retry is another model call. Every LLM judge is another model call on top of that. Keep the loop tight, and only retry when a retry is likely to help. If a particular input fails validation three times in a row, the problem is probably not the model—it is the request, the schema, or the task itself.
Build Your Loop
Here is your next step. Take one structured-output use case you already have—the one where you currently parse the JSON and hope for the best. Sketch the validation loop for it. Write down the schema checks, the content rules, and the banned values. Then walk through the likely failures and decide which exit path each one would take.
You will notice something quickly: most of your failures are predictable, and most of them have a deterministic fix. That is the point. Validation turns the unpredictable output of a language model into the predictable input your application can safely act on. The model drafts. You decide.
Knowledge check
Final check
Finish the article by checking the ideas you just learned.
References
Research updated Sep 7, 2026


