Originally published in Spanish on CloudAcademy.ar.
If you've put an LLM in the middle of an automated pipeline, you know the routine: ask for JSON in the prompt, add an example, beg for no extra text, and still get the occasional trailing comma, renamed field or "Sure, here's the JSON:" that breaks json.loads. So you add validation, retries and a forgiving parser, and the glue code ends up bigger than the business logic.
On October 20, 2026, AWS announced structured outputs for all Anthropic Claude models on Amazon Bedrock, on both the bedrock-runtime and bedrock-mantle endpoints. You define a JSON Schema and the response follows it, because the constraint is applied during token generation rather than checked afterwards.
TL;DR
- Two mechanisms: a JSON Schema output format (shapes the model's response) and strict tool use (
"strict": true, shapes tool-call arguments). You can use both in the same request. - It's constrained decoding. The first request with a new schema compiles a grammar (up to ~90 seconds), which is cached for 24 hours per account.
- Every object needs
additionalProperties: false. Max 12 optional properties and 16 union-typed/anyOfproperties. Nominimum/maximum, nominLength/maxLength, no recursive schemas. - Incompatible with citations on Anthropic models (400 error).
- No separate charge announced: you pay model tokens, and output usually gets shorter.
- Still check
stop_reason: hittingmax_tokenstruncates the JSON.
Why this matters now
Structured outputs on Bedrock isn't new. It went GA in February 2026 across several providers. The gap was coverage: the Claude 5 family wasn't supported for months. You could see it in the ecosystem. A July issue in Vercel's AI SDK reported Bedrock rejecting strict for claude-sonnet-5 with a 400, so the SDK limited native structured outputs to Claude 4.x. The day of the announcement, a new issue asked to enable it for Claude 5. Lesson: Bedrock supporting it doesn't mean your SDK sends it.
This launch closes that gap: every Claude model, both endpoints, plus batch inference, cross-Region inference and typed streaming events.
How it works
- Bedrock validates the schema against a JSON Schema Draft 2020-12 subset (unsupported feature: immediate 400).
- A new schema compiles into a grammar, which can take up to ~90 seconds. AWS recommends a client read timeout of at least 120 seconds.
- The grammar is cached for 24 hours per account. Changing only
name/descriptionkeeps the cache; structural changes don't. - The model can only emit tokens that keep the output valid.
Where the schema goes: output_config.format for InvokeModel and the Messages API (a JSON object), and outputConfig.textFormat for Converse (a JSON string inside structure.jsonSchema.schema).
Hands-on: alert triage on EKS with Claude Haiku 5.5
The example: Alertmanager sends a webhook to a pod on EKS, the pod asks Claude Haiku 5.5 to classify the alert group against a schema, and the JSON decides who gets paged.
Haiku 5.5 is what AWS suggests for fast, repetitive work like classification. I'm using the global inference profile, global.anthropic.claude-haiku-5-5, which is also the only way to reach Haiku 5.5 from sa-east-1.
Permissions via EKS Pod Identity (trust pods.eks.amazonaws.com, allow bedrock:InvokeModel on the inference profile and foundation model ARNs), then:
aws eks create-pod-identity-association --cluster-name production \
--namespace observability --service-account alert-triage \
--role-arn arn:aws:iam::123456789012:role/alert-triage-bedrock
The schema keeps everything in required to stay under the 12-optional limit, and uses ["string", "null"] where a value may be absent:
TRIAGE_SCHEMA = {
"type": "object",
"properties": {
"severity": {"type": "string", "enum": ["info", "warning", "critical"]},
"owner_team": {"type": "string", "enum": ["platform", "payments", "data", "frontend", "unknown"]},
"page_oncall": {"type": "boolean"},
"probable_cause": {"type": "string"},
"suggested_action": {"type": "string"},
"runbook_url": {"type": ["string", "null"], "format": "uri"},
"related_alerts": {"type": "array", "items": {"type": "string"}}
},
"required": ["severity", "owner_team", "page_oncall", "probable_cause",
"suggested_action", "runbook_url", "related_alerts"],
"additionalProperties": False
}
The call itself:
bedrock = boto3.client("bedrock-runtime", region_name="sa-east-1",
config=Config(read_timeout=120, retries={"max_attempts": 3, "mode": "adaptive"}))
resp = bedrock.invoke_model(
modelId="global.anthropic.claude-haiku-5-5",
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 1024,
"system": SYSTEM,
"messages": [{"role": "user", "content": "Alertmanager group:\n" + json.dumps(alerts)}],
"output_config": {"format": {"type": "json_schema", "schema": TRIAGE_SCHEMA}},
}),
)
body = json.loads(resp["body"].read())
if body["stop_reason"] != "end_turn":
raise RuntimeError(f"incomplete response: {body['stop_reason']}")
result = json.loads(next(b["text"] for b in body["content"] if b["type"] == "text"))
There's no jsonschema validation and no retry-on-malformed-JSON loop, because you don't need them. The one operational trick: warm up at pod start. Make one dummy call before the readiness probe goes green (I use periodSeconds: 5 and failureThreshold: 30), so grammar compilation happens during the rollout and not on the first real 3 a.m. alert. Run the receiver in parallel with your existing routing (continue: true) for a few weeks and compare decisions.
For agents that act, use strict tools. The enum on namespace and a pattern on the deployment name constrain what the agent can ask for. Ranges like 1 <= replicas <= 20 can't go in the schema, so they stay in code, and execution stays behind human approval.
Gotchas
- Short read timeouts kill the first request during grammar compilation.
- Low
max_tokensgives you truncated JSON even with structured outputs on. - Going past 12 optional properties returns
Schema is too complexafter up to ~90 seconds. - A missing
additionalProperties: falsein a nested object is an instant 400. - Citations plus structured outputs on Claude is a 400.
- Every structural schema change pays compilation again. Version schemas like API contracts.
- Check what your SDK actually sends: some strip
strictfor models they don't know about.
Pricing
No separate charge was announced; you pay the model's tokens. Anthropic's list prices per million tokens: Haiku 5.5 $0.10 input / $0.50 output (prompts up to 100K tokens), Sonnet 5.5 $2 / $10, Opus 5.5 $4 / $20. Check Bedrock's pricing table for your Region and profile. My estimate for 100,000 alert groups a month at ~1,500 input and 150 output tokens on Haiku: about $22.50/month. Batch inference is 50% cheaper for non-urgent work and supports structured outputs. Prompt caching also helps, and Sonnet 5.5 cache reads on Bedrock cost half as much since October 7, 2026.
Region and data residency
From São Paulo, Haiku 5.5 is only available through global cross-Region inference. That's fine for infrastructure alerts. For regulated data, check what a global profile implies first, and keep secrets and customer data out of alert annotations. Some geographic profiles don't support structured outputs for every model, so test with the exact profile your policy requires.
Is it worth it?
If you're using Claude on Bedrock for anything that ends in json.loads: yes. Add output_config, make the schema follow the rules, and delete your validation layer. For agents whose tools touch real systems, strict: true should be the default from today.
My take: the feature has existed since February. What's new is that it no longer depends on the model. While some Claude models supported it and others didn't, every model switch risked breaking parsing, and libraries had to maintain allowlists. With full coverage, moving from Haiku to Sonnet goes back to being a quality and cost decision, not a compatibility one. For platform teams, the pattern generalizes: a small model, a strict schema, enums that map to real decisions, and a human approving anything with impact. It's the most boring and safest way to put AI into an ops workflow, and I mean that as a compliment.
Resources
- What's New: structured outputs for Claude models
- AWS ML Blog: Structured outputs for Anthropic Claude models on Amazon Bedrock
- AWS ML Blog (Feb 2026): Structured outputs on Amazon Bedrock
- Docs: Claude structured outputs
- Docs: Get validated JSON results from models
- Anthropic model Region compatibility
- Vercel AI SDK issue #23605



Top comments (0)