fix(mcp): tag unmapped tool failures with their cause vocabulary (#2051) (#2135)

Closes #2051. errorCauseTag() shipped in #2027 written and tested but
wired to nothing. This connects it: the two execution catch paths (sync
call and task) now pass errorCause into mcp.tool_called, carrying the
SQLSTATE or coded-error code, else the error's class name, capped at 64
chars.

The rows this exists for are the UNKNOWN_ERROR residue, whose
errorMessage is the constant "Något gick fel. Försök igen." and whose
errorDetail is the English constant: 465 such rows in the last 30 days
(create_voucher 58 of its 60 failures, query_journal 122) with nothing
to cluster on. A five-character SQLSTATE is protocol vocabulary; a raw
driver message can quote row values from a constraint violation and
belongs in the server log, never in event_log, so the raw message is
deliberately not captured.

A plain `new Error(...)` tags null rather than 'Error': tagging
everything is the same as tagging nothing. Pre-execution denials (scope,
capability, validation, unknown tool) pass nothing because their
errorCode already is the cause.

Self-tested by unwiring one call site and watching the new test name it.


Claude-Session: https://claude.ai/code/session_01L3P2hr19PhQuCoTSGoegcY

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-09-01 22:07:46 +02:00
committed by GitHub
co-authored by Jakob Wennberg Claude Opus 5
parent 191fb2cfce
commit dd84d6c1bb
4 changed files with 71 additions and 2 deletions
+2 -1
View File
@@ -251,7 +251,8 @@ export type CoreEvent =
errorMessage: string | null // human-readable error message (truncated to 500 chars), null on success.
// Raw material for clustering real agent failures into curated gotchas:
// errorCode alone can't distinguish "period locked" from "unbalanced".
errorDetail: string | null // The specific English diagnostic, when message_sv is a generic registry
errorDetail: string | null
errorCause: string | null // errorCauseTag(err): SQLSTATE / coded-error code / error class name, <= 64 chars. The clustering key for rows whose errorMessage is the UNKNOWN_ERROR constant (#2051); never a raw driver message, which can quote row values. // The specific English diagnostic, when message_sv is a generic registry
// default that says nothing (VALIDATION_ERROR -> "Förfrågan innehåller
// ogiltiga uppgifter."). Null when it would only repeat errorMessage.
// Without it a 604-call outage looked identical to a typo in the logs: