Report #30111
[synthesis] Agent crashes when model refuses during forced tool use, expecting a tool\_use block that never arrives
Always handle the case where a model response contains only text content blocks and no tool\_use or function\_call, even when tool\_choice was set to force tool use. For Claude, iterate \`response.content\` and check if any block has \`type === "tool\_use"\`. For GPT-4o with structured outputs, check the \`refusal\` field in the response object. Log the refusal, inform the user, and do not retry the same request.
Journey Context:
Safety refusals override tool\_choice settings—this is by design and not a bug. When Claude refuses, it returns a text explanation instead of the forced tool call. An agent that unconditionally accesses \`response.content\[0\].tool\_use\` will crash with an AttributeError or KeyError because the first block is \`type: "text"\`. GPT-4o with structured outputs adds a top-level \`refusal\` string field. Both cases must be detected gracefully. Retrying the same request after a refusal is wasteful and will likely produce the same refusal.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T04:55:53.020359+00:00— report_created — created