Bugfix: Why are raw Claude API errors (tool_use/tool_result mismatch...

Documentation for Sessions

🐛 Bugfix: Why are raw Claude API errors (tool_use/tool_result mismatch...

Date: 2026-03-21
Time: 17:37:27 UTC
Session: gspace1-250.10
Agent: backend
Confidence: 97%
Status: ✅ Documented


📋 Decision Context

Question:

Why are raw Claude API errors (tool_use/tool_result mismatch, 400 status) being sent directly to WhatsApp users?

Task: S250: Fix raw API errors reaching WhatsApp users


🎯 Decision Made

Chosen:

Three-layer fix: (1) Agent loop no longer appends raw LLM errors to finalOutput — logs full error, returns graceful user message instead. (2) routeTaskResponse strips any [ERROR:...] patterns from output before sending to any channel — defense in depth. (3) Pre-send validation in agent loop scans all messages for orphaned tool_use IDs and injects synthetic tool_result blocks before calling Claude API — prevents the 400 error from occurring in the first place.

Options Considered:

  1. Only fix the error display (hide from users but don't prevent the 400)
  2. Only fix the tool_use pairing (prevent 400 but still expose other errors)
  3. Three-layer fix: prevent 400 + hide errors + graceful fallback (chosen)

💭 Reasoning

Root cause chain: (1) Agent loop catches SmartRouter failure at line 377, appends raw error to finalOutput: [ERROR: All LLM providers failed — ${err.message}]. (2) err.message contains full Claude API error detail including request IDs, tool IDs, JSON error bodies. (3) Channel processing treats this as successful output (task status = completed), routes it through routeTaskResponse. (4) sanitizeOutput only strips credentials/env vars, not API errors. (5) Raw error reaches WhatsApp user. The tool_use/tool_result mismatch itself likely occurs when context windowing or early breaks leave orphaned tool_use blocks. The S185 backfill (line 901) covers normal cases but not edge cases where messages are manipulated between iterations. The pre-send validation is the definitive fix — it runs right before every LLM call and ensures pairing is always correct.


📁 Files Involved


🔗 Related


Auto-generated by MCP Smart Consolidation