Summary
When a session crashes mid-tool-execution, resuming it fails with an Anthropic HTTP 400 error due to consecutive user-role messages in the API request. This creates an unresumable session that requires manual transcript surgery to fix.
Affected component: amplifier-core (session resume logic)
Reproduction
- Start a session with tool use
- Session crashes mid-tool-execution (network timeout, process kill, etc.) — leaving an assistant message with
tool_calls but no corresponding tool_result in the transcript
- Attempt to resume the session with
amplifier session resume <id>
- HTTP 400 from Anthropic
Root Cause
The resume logic strips orphaned assistant tool_use messages (correctly — can't send tool_use without tool_result). However, this leaves the preceding tool_result as the effective last message, which maps to role: "user" in the Anthropic API. The resume prompt is then appended as another role: "user" message, creating consecutive same-role messages that Anthropic rejects.
The sequence that fails:
[N-1] user (tool_result) ← was paired with the now-stripped tool_use
[N] user (resume prompt) ← injected by resume logic
→ HTTP 400: consecutive user messages
A similar collision occurs when hooks (e.g., hooks-status-context) inject user-role content between a tool_result and the next API call.
Observed Impact
- Session
ba107234-91eb-403f-a671-a668a3f614de required four manual transcript repairs due to this bug
- Each resume attempt hit HTTP 400, crashed again, and left additional corrupt state
- The only workaround is manual transcript truncation back to a safe assistant text message with no pending tool calls
Suggested Fix
When constructing the API request for a resumed session:
- After stripping orphaned tool calls, check if the effective last message is
role: "user"
- If so, either:
- Merge the resume prompt into the existing user message, OR
- Insert a synthetic assistant acknowledgment (e.g.,
"Resuming session.") before the resume prompt to maintain role alternation
- Apply the same merge logic when hooks inject
user-role content after a tool_result
More generally, the message construction pipeline should enforce role alternation as a post-processing step before sending to any provider that requires it.
Environment
- Platform: WSL2 (Linux 6.6.87.2-microsoft-standard-WSL2)
- Provider: Anthropic (claude-opus-4-6)
- Session: ba107234-91eb-403f-a671-a668a3f614de
Summary
When a session crashes mid-tool-execution, resuming it fails with an Anthropic HTTP 400 error due to consecutive
user-role messages in the API request. This creates an unresumable session that requires manual transcript surgery to fix.Affected component:
amplifier-core(session resume logic)Reproduction
tool_callsbut no correspondingtool_resultin the transcriptamplifier session resume <id>Root Cause
The resume logic strips orphaned assistant
tool_usemessages (correctly — can't send tool_use without tool_result). However, this leaves the precedingtool_resultas the effective last message, which maps torole: "user"in the Anthropic API. The resume prompt is then appended as anotherrole: "user"message, creating consecutive same-role messages that Anthropic rejects.The sequence that fails:
A similar collision occurs when hooks (e.g.,
hooks-status-context) injectuser-role content between atool_resultand the next API call.Observed Impact
ba107234-91eb-403f-a671-a668a3f614derequired four manual transcript repairs due to this bugSuggested Fix
When constructing the API request for a resumed session:
role: "user""Resuming session.") before the resume prompt to maintain role alternationuser-role content after atool_resultMore generally, the message construction pipeline should enforce role alternation as a post-processing step before sending to any provider that requires it.
Environment