#21195: fix: suppress orphaned tool_use/tool_result errors after session compaction
agents
size: M
Cluster:
Error Handling in Agent Tools
## Problem
When session compaction removes one half of a tool_use/tool_result pair, the next API call returns a 400 error that leaks raw to the user in chat.
**Anthropic:** `tool_use ids were found without tool_result blocks immediately after`
**OpenAI:** `No tool call found for function call output`
## Fix
Added regex pattern matching in `run.ts` to catch these orphaned tool result errors and return a friendly message instead of leaking raw API errors.
Patterns caught:
- `tool_call not found` / `tool_use_id not found`
- `function call output`
- `tool_use without tool_result`
Also includes delivery queue hardening:
- 30-min max-age for stale entries
- Permanent error detection (skip retry for non-retryable errors)
- 203 lines of tests
## Testing
Verified on 3 production instances (Mac + 2x Sofiia). Error no longer leaks to Telegram.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes two production issues: (1) suppresses orphaned tool_use/tool_result 400 errors after session compaction with user-friendly message, and (2) hardens delivery queue with 30-minute stale entry detection and permanent error detection to skip non-retryable failures.
**Changes:**
- Added regex pattern matching in `run.ts` to catch orphaned tool result errors from Anthropic/OpenAI and return "Session context was refreshed mid-operation" instead of raw API errors
- Added `orphaned_tool_result` error kind to type definitions
- Delivery queue now skips entries older than 30 minutes (moved to failed/)
- Permanent errors (message too long, bot blocked, token missing, etc.) are immediately moved to failed/ without consuming retry budget
- Added 203 lines of test coverage for delivery queue hardening
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The changes are well-contained, defensive, and thoroughly tested. Error handling is conservative (catches specific patterns, logs warnings, returns user-friendly messages). Delivery queue hardening prevents wasted retry cycles on permanent errors and stale messages. The regex pattern is comprehensive and matches documented error formats from multiple providers. Test coverage is excellent with 203 new lines covering edge cases.
- No files require special attention
<sub>Last reviewed commit: 1ce7165</sub>
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#20538: fix: handle orphaned tool_result errors gracefully instead of leaki...
by echoVic · 2026-02-19
87.9%
#12487: fix(agents): strip orphaned tool_result when tool_use is sanitized ...
by skylarkoo7 · 2026-02-09
85.8%
#14328: fix: strip incomplete tool_use blocks from errored/aborted messages...
by Kropiunig · 2026-02-12
85.8%
#11825: fix: keep tool_use/tool_result pairs together during session compac...
by C31gordon · 2026-02-08
84.8%
#15050: fix: transcript corruption resilience — strip aborted tool_use bloc...
by yashchitneni · 2026-02-12
84.1%
#3362: fix: auto-repair and retry on orphan tool_result errors
by samhotchkiss · 2026-01-28
84.1%
#13062: fix: remove orphaned tool_result blocks from user message content d...
by trevorgordon981 · 2026-02-10
83.5%
#4844: fix(agents): skip error/aborted assistant messages in transcript re...
by lailoo · 2026-01-30
83.2%
#19094: Fix empty tool_call_id and function names in provider transcript pa...
by yxshee · 2026-02-17
83.0%
#16095: fix: remove orphaned tool_result blocks during compaction (#15691)
by claw-sylphx · 2026-02-14
83.0%