Amazon Bedrock Structured Outputs Are Not a Finished Record

A missing comma has stalled more AI automation work than a bad strategy deck. Take that as a joke with a kernel of truth. The model answers. The CRM write fails. The agent retries. Somewhere in the logs, a cheerful sentence sits in front of what was supposed to be JSON. The bill reflects every attempt to recover from it.

Amazon Bedrock documents a tighter contract for Anthropic’s Claude models: structured outputs. You supply a schema. Constrained decoding keeps a successful completion inside that shape while tokens are produced, instead of leaving a parser to salvage free text afterward. The Bedrock user guide is the document to trust before you bet a sales pipeline or a ticket router on it. Support depends on the model, and on the inference profile you actually call.

Two contracts, not one switch

There are two mechanisms, and they fail in different places. Anthropic draws the line as what Claude says versus how Claude calls a function. Amazon Web Services documents the same split.

A JSON Schema response format controls the reply. Use it when the product of the call is data: a lead record, a support classification, a report broken into typed fields, an API payload another system will ingest. On bedrock-runtime, InvokeModel, streaming InvokeModel, Converse, and ConverseStream all support it. In the Anthropic-native request body, the documented InvokeModel pattern passes the schema as a JSON object, not a stringified blob. The Converse example goes the other way and passes the schema as a JSON string. Mix those up and you will spend an afternoon arguing with a 400.

Strict tool use controls the call. With strict set to true, tool names and tool inputs have to match the tool schema. A lookup that must receive a location and a unit of either celsius or fahrenheit is the toy version of the real pattern: create a record, update a ticket, book a meeting. Schema-valid arguments are how multi-step AI agents stop inventing parameters your function cannot accept.

You can use both in one request. Standardize on that pattern. Strict inputs on the way into tools. A structured object on the way out, so the next system is not parsing a paragraph.

For sales and service work, the payoff is concrete. A classifier that must return a category, a priority, a sentiment, an escalate flag, and a short reason can route a ticket without a pile of brittle text matching. A lead extractor that must return a name, an email, a plan, and whether a demo was requested can land in a CRM as a record instead of a note. That is the unglamorous win in AI for sales: the handoff becomes machine-readable, which is the part that usually fails first.

The operating rule, before the mechanics

Start with a small, closed schema and set additionalProperties to false on every object. Prefer enums wherever the business already has a controlled vocabulary. Keep that schema stable across the steps that repeat, because a new or structurally changed schema is a compile, not a free extra millisecond.

Separate what the grammar guarantees from what the business requires. Types, required fields, and supported enums belong in the schema. Ranges, lengths, foreign keys, case, and policy live in your service. Check the stop reason before you write anywhere a human will not be watching.

The first call is a build

The Bedrock path is validate, compile, cache, then infer. On a normal completion, the model is not free to wander and get graded later. Tokens that would break the schema are not produced. Read that narrowly. It covers a finished completion that was not refused and was not cut off. It does not cover a safety refusal, an object truncated at the token limit, or a string enum that differs only in case.

Some write-ups frame this as formatting turning from probabilistic to deterministic, and as a reason to drop extra validation. Constrained is the accurate word. Ordinary completions come back schema-shaped. They are not infallible. They are not automatically factual. And they are not a substitute for your business rules.

A new schema is compiled into a grammar before generation. The Bedrock user guide says that first compilation can take up to a few minutes. Compiled grammars are cached for 24 hours from first access and reused when the same account sends an identical schema. After that, AWS describes latency as comparable to ordinary inference, with minimal overhead. AWS confirms same-account reuse. Do not assume the cache is shared across regions or endpoints.

Anthropic’s structured-outputs docs are explicit that editing only a name or a description does not force a recompile, while a structural change does. Stable schemas are a latency strategy, not a style preference. If every request invents a slightly different object, a workflow sold as real time starts with a build step.

If you also call Claude on Anthropic’s own platform, do not merge the two cache stories. There, the documented window is 24 hours from last use, and combining structured output with tools can invalidate the cache when the tool set changes. On Bedrock, what is confirmed is same-account reuse of identical schemas, measured from first access.

What the schema will police, and what it will not

Bedrock validates schemas against a supported subset of JSON Schema draft 2020-12. The user guide says unsupported features return an immediate 400. That matters, because some announcement language sounds softer, as if certain keywords are accepted and then ignored during generation. Design to the user guide. If a constraint is not in the supported set, do not ship it and hope.

The failure mode this prevents is a confident write of data your service cannot trust. A schema-valid email is not a deliverable email. A schema-valid contract date is not the date counsel would pick. Split the work.

Enforce in the schema

  • Ordinary types: object, array, string, integer, number, boolean, and null.
  • Required fields, with additionalProperties set to false on every object. Any other setting is unsupported, and schemas copied from APIs that allow extension fields will be rejected.
  • Enums of strings, numbers, booleans, or null, plus const, anyOf, and internal references through $ref, $def, and definitions.
  • String formats covering date-time, time, date, duration, email, hostname, uri, ipv4, ipv6, and uuid.

Enforce in your service

  • Numerical bounds, string length, recursive shapes, and external references. These are not a production control on this path.
  • Whether an ID exists, whether a value is allowed by policy, and whether an extracted fact is the right fact.
  • Capitalization. Anthropic documents that string enums and const values are not capitalization-guaranteed. The model may differ from the schema only in case, often at the first letter of a word after a space. If your enum is Enterprise and you reject enterprise, the grammar will not save you.
  • Key order, if a downstream parser secretly depends on it. Anthropic documents that required properties are emitted before optional ones, with schema order preserved inside each group. Make every property required, or teach the parser to tolerate reordering.

A few limits are easy to miss. Anthropic’s docs say allOf combined with $ref is not supported, and array minItems is only for 0 and 1. Bedrock describes allOf as supported with limitations and does not spell that $ref case out as clearly, so test the construct before you build a schema inheritance tree on it. Do not assume the default keyword is enforced on Bedrock just because Anthropic lists it for the Claude API. And do not pair structured outputs with citations. Anthropic documents that enabling both returns a 400.

A 200 is not a finished record

Two exits still produce output that does not match the schema, and both can arrive with an HTTP 200. Finance and engineering should hear that detail in the same meeting.

A safety refusal uses the stop reason refusal. Anthropic says those tokens are billed. A property that asks the model to expose its step-by-step thinking can also trigger a reasoning_extraction refusal. The practical guidance is to ask for a short explanation if you need one, and to keep extended reasoning in thinking blocks rather than in a schema field that solicits the chain of thought.

Hitting the token limit is the other trap. If generation stops because it reached max_tokens, the JSON can be cut off mid-object. The documented remedy is to retry with a higher limit. Branch on the stop reason. end_turn is the completion you wanted. max_tokens and refusal are not. Any code that only checks the HTTP status will load a fragment into a database and call it automation.

Batch inference is documented as supported, and the same stop-reason checks still apply. Cross-Region inference on bedrock-runtime is documented as available without a separate structured-outputs setup. That is not a promise about every profile. AWS says you should confirm support on each model card. Some geographic cross-Region profiles do not support structured outputs for every model, including Claude Haiku 4.5 through the India profile under the in.anthropic prefix. If the rollout is global, that exception list is part of the design.

Amazon Bedrock Mantle needs the same kind of check, not a separate architecture debate. The current Bedrock user guide lists the Anthropic Messages API on bedrock-mantle as supporting structured outputs through the output-format control. An AWS re:Post thread reports requests using that parameter failing with a 400, on the grounds that output_config.format was an extra input that was not permitted. A documented feature and a live 400 can both be true during an uneven rollout. Confirm the endpoint, model, and profile in the account you will run. If Mantle rejects the format field, a reply on that thread suggested forcing a tool with tool_choice. Treat that as a temporary bridge, not the design. It does not remove the stop-reason check.

Cost, without a number you can take to finance

Fewer malformed replies means fewer retries, and retries are where a lot of inference spend hides. That is a fair operational argument. It is not a measured discount.

Nothing in the published Bedrock or Anthropic material quantifies token savings or dollar savings. Anthropic’s documentation points the other way on input size: structured outputs inject an additional system prompt, so input tokens rise slightly, and changing the output format invalidates that conversation’s prompt cache. That is the prompt cache, not the grammar cache. Refusal tokens are still billed. Grammar compilation is a latency cost even when the token meter is quiet. Net cost is an empirical question for your prompts, your cache hit rate, and your failure rate before the change. Run that comparison. Do not put a lower inference bill on a steering slide until you have the number from your own traffic.

Questions worth settling before you standardize

  • Does a valid schema mean the answer is true? No. Constrained decoding polices shape on a completed response. It does not check that an extracted date is the right date, or that a sales classification matches your playbook.
  • Can we delete our parsers and validators? You can drop a lot of repair logic for missing braces and stray prose. You still need stop-reason handling, a retry when the token limit cuts the object short, and your own checks for rules the grammar does not enforce.
  • Will every Claude model and every Region just work? No. Confirm the model card and the inference profile. Batch and cross-Region inference are documented, with known profile exceptions, including Haiku 4.5 on at least one India cross-Region profile.
  • Why is the first request slow? Because the first use of a schema is a compile. The Bedrock user guide puts that delay at up to a few minutes, then caches the grammar for 24 hours from first access in that account. Do not generate a fresh schema inside a live request.
  • What should we verify before standardizing on Mantle? The exact endpoint, model, and profile in the account you will run. The user guide says the Messages API on Mantle supports the output-format control, and at least one reported deployment returned a 400. Test the call. If the format field is rejected, tool_choice is a temporary bridge, not the design.
  • Will this cut our AI automation bill? It can, if retries were the expensive part. Input tokens can also rise, refusals are billed, and no public figure in the documentation shows a net saving. Measure it.

Schema-shaped output is the part of AI for business you can actually standardize. Judgment stays yours, and so do the rules the grammar will not enforce. The first production incident will probably be a model that spoke perfect JSON, in the wrong capitalization, under a 200, after a refusal nobody branched on. A model that simply refused to speak JSON is the less likely story.