`--json-schema` with `"format": "uri"` silently disables synthetic structured-output tool
Summary
When the schema passed to claude -p --json-schema … contains a string property with "format": "uri", the model declines to invoke the synthetic structured-output tool entirely. The requested value lands in the response envelope's result field as plain text instead, leaving structured_output: null.
Removing the format: "uri" annotation (or replacing the property's type) restores tool invocation. No other JSON Schema feature investigated has the same effect — title, description, additionalProperties, required-list shape, field name, ordering, nesting, and field-level descriptions all leave behavior unchanged.
claude --version: 2.1.136 (Claude Code)- Model:
claude-opus-4-7[1m](reproduces onclaude-opus-4-6too) - Reproduction rate: 100% across 16 controlled schema mutations + dozens of end-to-end pipeline runs
Self-contained reproduction
Three small files; two claude CLI invocations with identical flags except the schema content.
Files
agent.md
# URL Reporter
You receive a URL value in the user message and emit it as structured output.
schema-bad.json — has "format": "uri"
{
"type": "object",
"required": ["url"],
"properties": {
"url": { "type": "string", "format": "uri" }
}
}
schema-good.json — identical except for the missing format annotation
{
"type": "object",
"required": ["url"],
"properties": {
"url": { "type": "string" }
}
}
Negative test (reproduces the bug)
PROMPT="The URL is https://example.com/pr/42. Emit it as structured output."
claude -p "$PROMPT" \
--agent agent.md \
--output-format json \
--no-session-persistence \
--dangerously-skip-permissions \
--json-schema "$(cat schema-bad.json)"
Observed envelope (relevant fields):
subtype: success
structured_output: null
result: "https://example.com/pr/42"
The synthetic structured-output tool is never invoked. The URL value the model was asked to emit lands in result as a plain string.
Positive test (works as expected)
Same command, only schema-bad.json swapped for schema-good.json:
claude -p "$PROMPT" \
--agent agent.md \
--output-format json \
--no-session-persistence \
--dangerously-skip-permissions \
--json-schema "$(cat schema-good.json)"
Observed envelope:
subtype: success
structured_output: {"url": "https://example.com/pr/42"}
result: "Emitted."
Expected behavior
Both invocations should produce identical structured_output envelopes — {"url": "https://example.com/pr/42"}. JSON Schema's format keyword is, by spec (Draft-07 §7.1), an annotation: it should not affect whether the synthetic tool is invoked, only whether the produced value passes downstream validation.
Actual behavior
Adding "format": "uri" to a string property suppresses the synthetic tool entirely. The model writes the value the schema asked for into the result field as plain text and structured_output stays null. The CLI exits with subtype: success, so callers downstream cannot tell that structured emission silently failed.
Diagnostic notes
This was isolated by running 16+ controlled schema mutations through identical CLI invocations and comparing structured_output populated vs. null:
| Mutation | Result |
|---|---|
| format: uri removed (any other change held) | structured_output populated |
| Field type changed from string to integer (URL field becomes ID) | populated |
| Field type changed to array of strings | populated |
| Field type changed to string with enum constraint | populated |
| Field renamed (e.g., pr_url → link / evidence / value) but format: uri kept | null (bug reproduces) |
| pr_url field nested inside an array-of-objects, format: uri retained | null |
| Schema-level description added | null (no help) |
| Field-level description added | null (no help) |
| additionalProperties: false added | null (no help) |
| Property reordered to last | null (no help) |
| required reduced to ["outcome"] only, format kept on a separate optional field | null (no help) |
The single attribute that determines emission is "format": "uri". This pattern persists across schemas with different titles, different field counts, different required-list shapes, and different surrounding properties.
Repro package contents
The accompanying repro.sh runs both the negative and positive tests back-to-back and summarizes the relevant envelope fields.
agent.md - minimal system prompt (one paragraph)
schema-bad.json - schema with "format": "uri"
schema-good.json - schema without "format": "uri"
repro.sh - bash runner that executes both tests
sample-output.txt - captured output from a real run
Sample run output:
==========================================================
NEGATIVE — schema with "format": "uri" (bug reproduces)
==========================================================
subtype: success
structured_output: None
result: 'https://example.com/pr/42'
==========================================================
POSITIVE — same schema without "format": "uri"
==========================================================
subtype: success
structured_output: {'url': 'https://example.com/pr/42'}
result: 'Emitted.'
Impact
This makes structured-output mode unusable for any schema modeling external resources (PR/MR URLs, document links, webhook callback URLs, signed-URL outputs, etc.) when authors follow JSON Schema best practices and annotate string fields with format: "uri". The only working remedy we found — omitting the annotation entirely — trades schema clarity for working tool invocation.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗