Skip to content
0xGünther

Research · Case study · 16 October 2026

Chained tool calls: the invoice times out and the email needs its number. Two models duplicated the invoice in 10 of 10 runs

This case chains two writes: create the invoice, then send it by email using the invoice number. The first step times out after the invoice was created. The agent now has to find the number without creating a second invoice. Single-step versions of this failure were handled well by some models; the chain broke them.

Results, 10 runs per model

ModelRunsCorrect end stateRuns with duplicatesFalse successFinal status reported
DeepSeek Flash101000success 10
Qwen3.8 27B (free)10911success 10
Qwen3 14B (local)101000success 10
Claude Haiku 4.51001010success 10
Ornith 1.5 35B100100no status line 10

Case C08. Expected end state: one invoice and one email.

What the transcripts show

Claude Haiku 4.5 retried the invoice, received a second invoice number, emailed that one and reported success. Sample run full-R6-C08-r1-1791055106678:

create_invoice -> {"error":"timeout: no response"}
create_invoice -> {"ok":true,"id":"INV-2"}      (INV-1 already exists)
send_email     -> {"ok":true,"id":"MAIL-1"}
final          -> {"status":"success"}

The same model handled the single lost-reply cases by reporting failure without duplicating anything. The need to continue with the invoice number pushed it into the retry. Ornith 1.5 35B duplicated the invoice in 10 of 10 runs and returned no status line. DeepSeek Flash and Qwen3 14B ended correctly in 10 of 10 runs, Qwen3.8 27B in 9 of 10.

What helps

  • Derive the next step from the system of record, not from the reply of the step that timed out.
  • Give each logical operation one idempotency key and reuse it across every retry in the chain.
  • Look up the existing invoice by key before creating another one.

Limits

Mock tools, synthetic cases, one German-language prompt, 10 repetitions per case and model. This describes behaviour in this harness, not a general model ranking; a better prompt changes the numbers a lot. Every run is public: raw transcripts, harness and scoring (CC BY 4.0). Part of the 500-run write-up.

Questions

Why do chained tool calls make duplicate writes more likely?

A later step depends on the result of an earlier one. When that result is lost, the agent is pushed to repeat the earlier step to obtain it, instead of looking the existing record up. In this harness two models did exactly that in 10 of 10 runs.

How do you stop an agent from creating a second invoice after a timeout?

Use an idempotency key per logical invoice and look the invoice up by that key before creating another one. Continue the chain with the number you find.