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
| Model | Runs | Correct end state | Runs with duplicates | False success | Final status reported |
|---|---|---|---|---|---|
| DeepSeek Flash | 10 | 10 | 0 | 0 | success 10 |
| Qwen3.8 27B (free) | 10 | 9 | 1 | 1 | success 10 |
| Qwen3 14B (local) | 10 | 10 | 0 | 0 | success 10 |
| Claude Haiku 4.5 | 10 | 0 | 10 | 10 | success 10 |
| Ornith 1.5 35B | 10 | 0 | 10 | 0 | no 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.