fix(server): include SQLite conditions in persistence errors - #9536
Conversation
toPersistenceSqlError set the detail to "Failed to execute <operation>", so the rendered message repeated the operation and dropped the only part worth reading. Errors.test.ts already asserts the opposite intent in a test named "keeps SQL operation context without a tautological detail". Carry the cause instead: a schema failure contributes its issue tags, which hold no rejected values, and a driver failure contributes its own message, which names the SQLite condition rather than any bound value. A cause with nothing to say leaves the detail unset, which the message already handles. Refs #4818. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review feedback: copying cause.message into detail put unbounded driver text into a direct error attribute, and a constraint failure spells out the table and column it hit. SQLite names its condition through a fixed result-code table, so errcode and errstr are bounded and carry no query data. Carry that pair instead, read through the wrapping driver error, and leave the detail unset for a cause the mapper cannot categorize. The full text stays on cause. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Handle Bun errno separately from the Node SQLite fields. Test a real Node SQL failure and wrapped Bun errors without copying query data.
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a focused persistence diagnostics fix that preserves the original cause and operation while adding normalized SQLite condition details without exposing query values. Its only production effect is bounded error-message formatting, with focused coverage and no changes to defaults, schemas, workflows, or execution behavior. You can add or adjust custom eligibility rules. Learn more. |
Persistence SQL errors repeat the operation name and hide the cause.
Include Node's fixed SQLite description, Bun's numeric error code, or schema issue tags without copying driver messages or rejected values. This improves diagnosis. It does not fix the database failure reported in issue #4818.
Continues @Sy-D's #4837. The original commits and co-author credit are preserved. This adds the missing Bun handling and tests through the SQL client.
Verified with 14 focused tests, server typecheck, changed-file lint and formatting, and real in-memory Node and Bun failures.
Created with GPT-6 Astra (preview) in Codex.
Note
Low Risk
Diagnostics-only change in the persistence error mapper; behavior for uncategorized errors matches omitting detail, with no query or auth logic changes.
Overview
toPersistenceSqlErrorno longer sets a tautologicaldetail(Failed to execute …). It now derives optionaldetailfrom the cause: normalized SQLite conditions (Nodeerrcode/errstror BunSQLiteErrorerrno, walking a shortcausechain), or schema issue tags when the failure is aSchemaError. Driver text, query values, and rejected payloads stay out ofmessage/detail.Tests cover in-memory constraint failures, wrapped Node driver errors, Bun errors behind
SqlError, uncategorizable causes (no detail), and schema mapping without leaking sentinels.Reviewed by Cursor Bugbot for commit 577b098. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Include SQLite conditions in
toPersistenceSqlErrorpersistence diagnosticssqliteConditionhelper in Errors.ts that traverses the cause chain (up to four wrappers) and recognizes Node SQLite errors by numericerrcode+errstrand BunSQLiteErrorby integererrno; driver messages are not read for classificationdescribeSqlCausehelper that routes schema causes to the existing issue-tag summarizer and all other causes to the SQLite condition extractor, returningundefinedwhen neither appliestoPersistenceSqlErrornow derives detail from these helpers and no longer assigns a fixed failed-operation detail to every cause; operation and original cause remain attachedtoPersistenceSqlErrorno longer emits detail for uncategorized causes — callers that relied on the previous fixed detail string will seePersistenceSqlErrorwith no detail for non-SQLite, non-schema errorsMacroscope summarized 577b098.