`--json-schema` with `"format": "uri"` silently disables synthetic structured-output tool

Resolved 💬 1 comment Opened May 10, 2026 by SinishaDjukic Closed Jun 8, 2026

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 on claude-opus-4-6 too)
  • 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_urllink / 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.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗