Skip to content

Compaction permanently fails with 'Duplicate value for tool_call_id' after an interrupted tool run #40235

Description

@diegomcolucci

Summary

An aborted/interrupted tool run leaves a second tool part with the same callID in the message. The next auto-compaction then re-sends the full history to the provider and fails with 400 invalid_request_error: Duplicate value for 'tool_call_id', so compaction never completes (summary never written, token counter never resets). The session is effectively poisoned — every subsequent compaction fails the same way.

Root cause evidence (local sqlite DB, opencode v1.18.11)

One assistant message contains two tool parts sharing the same callID: a completed one (tool=todowrite) and an error one (tool=unknown, error: "Tool execution aborted", metadata.interrupted: true).

Message msg_fb9813f84... (session ses_0507e87b...):

  • part prt_fb9814a85...: {"type":"tool","tool":"todowrite","callID":"functions.todowrite:1","state":{"status":"completed",...}}
  • part prt_fb9816675...: {"type":"tool","tool":"unknown","callID":"functions.todowrite:1","state":{"status":"error","input":{},"raw":"","error":"Tool execution aborted","metadata":{"interrupted":true},...}}

Message msg_fc35e22d5... (same session):

  • part prt_fc35e5d6d...: {"type":"tool","tool":"todowrite","callID":"functions.todowrite:0","state":{"status":"completed",...}}
  • part prt_fc35e7502...: {"type":"tool","tool":"unknown","callID":"functions.todowrite:0","state":{"status":"error","input":{},"raw":"","error":"Tool execution aborted","metadata":{"interrupted":true},...}}

The unknown part with Tool execution aborted is written when a run is interrupted; it duplicates the callID of the tool call that was already recorded as completed.

Failure symptom

Two consecutive auto-compactions in the same session failed identically:

  1. msg_fb9e6c8bf... (compaction, finish=None, err=true):
    Error from provider (DeepSeek): Duplicate value for 'tool_call_id' of functions.todowrite:1 in message[53] (400)
  2. msg_fc45786f2... (compaction, finish=None, err=true):
    Error from provider (Console): Upstream request failed: [invalid_request_error] Duplicate value for 'tool_call_id' of functions.todowrite:0 in message[224] (400)

Log excerpt:

timestamp=...T21:18:22.176Z level=ERROR ... agent=compaction mode=primary
  error.error="AI_APICallError: Error from provider (Console): Upstream request failed: [invalid_request_error] Duplicate value for 'tool_call_id' of functions.todowrite:0 in message[224]"

Because compaction serializes the entire history head to the model, the duplicate is always present → compaction aborts before producing a summary → the message count / token counter keep growing and the session never recovers, even though compaction.auto and prune are enabled.

Expected behavior

  • Tool parts must be deduplicated by callID before building model messages (drop the unknown/interrupted duplicate, keep the completed one), or
  • interrupted runs should not write a second tool part with an existing callID at all.

Impact

Sessions that suffer an interrupted tool run become permanently un-compactable (until a fresh session). Auto-compaction then loops on the same 400, the token counter stays high, and the user is forced to /new.

Repro notes / workaround

  • Took the evidence from ~/.local/share/opencode/opencode.db (tables message, part; parts of type tool with duplicate callID where one is tool="unknown", error="Tool execution aborted").
  • Workaround for the affected session: delete the duplicate unknown/interrupted tool part (keep the completed one) while opencode is closed.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions