[BUG] SDK Stop hook: structured output enforcement skipped on resumed sessions (--resume + --json-schema)

Resolved 💬 4 comments Opened Mar 27, 2026 by pedrohugorm Closed May 1, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When using the Claude Agent SDK (Python) with --resume and --json-schema, the CLI's built-in StructuredOutput stop hook enforcement only fires once per session. On resumed sessions, the enforcement is skipped and structured_output is null in the result.

Steps to reproduce:

  1. Start a session with output_format (json_schema) configured
  2. Send a prompt — agent calls StructuredOutput correctly (enforcement fires)
  3. Resume the same session with --resume <session_id> and the same output_format
  4. Send another prompt — agent responds with text but never calls StructuredOutput
  5. Result has structured_output: null

Environment:

  • Claude Code: latest
  • SDK: claude-agent-sdk (Python)
  • OS: macOS

The CLI's internal StructuredOutput-called flag appears to persist across the session. Once satisfied on the first prompt, it's never reset for subsequent prompts on resumed sessions.

What Should Happen?

The StructuredOutput enforcement should fire on every prompt where --json-schema is set, regardless of whether the session is new or resumed. The internal flag tracking whether StructuredOutput was called should reset at the start of each turn.

Workaround

Use {"decision": "block", "reason": "You MUST call the StructuredOutput tool..."} in an SDK Stop hook callback when the session is resumed and output_format is set. This matches the shell hook pattern used in .claude/settings.json Stop hooks.

Important: {"continue_": False} (Python) / {"continue": false} does NOT work for SDK callback Stop hooks — it terminates the session instead of giving Claude another turn. The decision: "block" mechanism is the correct way to prevent a stop from SDK callbacks.

Error Messages/Logs

# First prompt (new session) — works
[stop_hook] stop_hook_active=False  → CLI enforcement fires
[tool_use] StructuredOutput called
[stop_hook] stop_hook_active=True   → enforcement satisfied
[result] structured_output={"answer": "4", "confidence": 1}

# Second prompt (resumed session) — fails without workaround  
[stop_hook] stop_hook_active=False  → CLI enforcement does NOT fire
[result] structured_output=null

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗