Filed unassigned by the #16019 dev (PR #16650, patch round), at the contract reviewer's disposition: "filed, not noted". ⛔ No label, no severity asserted — routing is triage's. Not a leak and not a classification change; an operator-diagnostics regression on a named set of sites, with the remedy known.
What changed upstream
Since PR #16650, SqlDriver.execute() — the raw-SQL seam every migration probe, backfill and cli db clean runs through — declares a backend refusal instead of letting the dialect's error object out: code: DATABASE_ERROR, status: 500, a COMPOSED message ("The database refused to run a raw statement. …"), the dialect error whole under a NON-ENUMERABLE cause, and the statement plus dialect text written to the driver's warn sink (default console.warn) before composing. TursoDriver remote mode declares the same way.
⇒ Every consumer that embedded error.message of a raw-exec failure into an operator-facing record now embeds the composed sentence. The dialect's words are one cause away (and printed one line earlier on any default deployment), but the structured detail / error field an operator reads has lost them.
The sites — measured on origin/main 4fe00b80e7 (line numbers by grep -n, re-derive by symbol)
-
packages/metadata-protocol/src/migrations/runtime-index-preflight.ts:298 — return unreadable(error instanceof Error ? error.message : String(error)) (the per-probe detail); :337 — seamFailure = error instanceof Error ? error.message : String(error).
-
packages/metadata-protocol/src/migrations/seed-tenancy-backfill.ts:1184 (detail), :1259 (status: 'absent', detail: (e as Error).message), :1305 (organizationProbeError), :1388 / :1414 / :1447 ({ error: (e as Error).message } result records).
-
packages/metadata-protocol/src/migrations/partial-index-probe.ts:37 and :359 — the module note says this module "hands back a classified status plus the driver's own text", and the comment at :359 says "detail is the OPERATOR-facing text and stays the driver's own prose". Both now state the opposite of what happens: detail is the composed sentence. The classification itself is unaffected (classifyIndexFailure is cause-following).
-
packages/cli/src/commands/db/clean.ts:115 — printError(VACUUM failed for ${file}: ${error?.message ?? error}); the dialect text still reaches the console through the driver's default warn sink, printed first, so this one is cosmetic.
- The four migration result records that store
err.message after a raw-exec failure: packages/metadata/src/migrations/{migrate-env-id-to-project-id,migrate-sys-notification-to-event,drop-projection-tables,migrate-project-id-to-environment-id}.ts.
Correction after the delta review of PR #16650 (card #16019, comment 5574921392): the first version of this card also listed metadata-protocol/src/migrations/overlay-index.ts, sys-setting-identity-index.ts and protocol.ts (around :5654-5670). Those three are swallow-only catches — a bare catch { fallback = 'refused'; }, catch { return false; }, a bare catch { — and store no err.message; they are dropped, and the list above is the verified set.
Positive control for the census: remote-transport.ts's no such column sniff (2 hits) fires on the same expressions; the reviewer's independent survey S1/S8 on PR #16650 enumerated the same raw-exec set.
Remedy
At each site, derive the operator-facing text from the cause chain when the thrown error declares DATABASE_ERROR — one small helper (walk cause to the first node whose message is not the composed sentence, depth-bounded like matchesDriverError) — and correct the two partial-index-probe.ts comments to say what the detail now carries. ⛔ Do not read the dialect text back into error.message at the driver: the composed message is the disclosure clause of the raw-path envelope (PR #16650's driver docblock says why), and these sites are operator surfaces that can read cause directly.
Evidence
Related
#16019 · PR #16650 · #8931 / PR #9273 (the same envelope on the typed read exits, where no such operator record existed)
Filed unassigned by the #16019 dev (PR #16650, patch round), at the contract reviewer's disposition: "filed, not noted". ⛔ No label, no severity asserted — routing is triage's. Not a leak and not a classification change; an operator-diagnostics regression on a named set of sites, with the remedy known.
What changed upstream
Since PR #16650,
SqlDriver.execute()— the raw-SQL seam every migration probe, backfill andcli db cleanruns through — declares a backend refusal instead of letting the dialect's error object out:code: DATABASE_ERROR,status: 500, a COMPOSED message ("The database refused to run a raw statement. …"), the dialect error whole under a NON-ENUMERABLEcause, and the statement plus dialect text written to the driver's warn sink (defaultconsole.warn) before composing.TursoDriverremote mode declares the same way.⇒ Every consumer that embedded
error.messageof a raw-exec failure into an operator-facing record now embeds the composed sentence. The dialect's words are onecauseaway (and printed one line earlier on any default deployment), but the structureddetail/errorfield an operator reads has lost them.The sites — measured on
origin/main4fe00b80e7(line numbers bygrep -n, re-derive by symbol)packages/metadata-protocol/src/migrations/runtime-index-preflight.ts:298—return unreadable(error instanceof Error ? error.message : String(error))(the per-probedetail);:337—seamFailure = error instanceof Error ? error.message : String(error).packages/metadata-protocol/src/migrations/seed-tenancy-backfill.ts:1184(detail),:1259(status: 'absent', detail: (e as Error).message),:1305(organizationProbeError),:1388/:1414/:1447({ error: (e as Error).message }result records).packages/metadata-protocol/src/migrations/partial-index-probe.ts:37and:359— the module note says this module "hands back a classified status plus the driver's own text", and the comment at:359says "detailis the OPERATOR-facing text and stays the driver's own prose". Both now state the opposite of what happens:detailis the composed sentence. The classification itself is unaffected (classifyIndexFailureis cause-following).packages/cli/src/commands/db/clean.ts:115—printError(VACUUM failed for ${file}: ${error?.message ?? error}); the dialect text still reaches the console through the driver's default warn sink, printed first, so this one is cosmetic.err.messageafter a raw-exec failure:packages/metadata/src/migrations/{migrate-env-id-to-project-id,migrate-sys-notification-to-event,drop-projection-tables,migrate-project-id-to-environment-id}.ts.Correction after the delta review of PR #16650 (card #16019, comment 5574921392): the first version of this card also listed
metadata-protocol/src/migrations/overlay-index.ts,sys-setting-identity-index.tsandprotocol.ts(around:5654-5670). Those three are swallow-only catches — a barecatch { fallback = 'refused'; },catch { return false; }, a barecatch {— and store noerr.message; they are dropped, and the list above is the verified set.Positive control for the census:
remote-transport.ts'sno such columnsniff (2 hits) fires on the same expressions; the reviewer's independent survey S1/S8 on PR #16650 enumerated the same raw-exec set.Remedy
At each site, derive the operator-facing text from the
causechain when the thrown error declaresDATABASE_ERROR— one small helper (walkcauseto the first node whose message is not the composed sentence, depth-bounded likematchesDriverError) — and correct the twopartial-index-probe.tscomments to say what thedetailnow carries. ⛔ Do not read the dialect text back intoerror.messageat the driver: the composed message is the disclosure clause of the raw-path envelope (PR #16650's driver docblock says why), and these sites are operator surfaces that can readcausedirectly.Evidence
execute()sees": the class is declared there and this card is cited by number; this card is the follow-up it names.no such column:but notno such function:— a SQLite parse failure echoes the raw engine message into the 500 body #16019, comment 5573043610), section ⑤: "the disposition should be 'filed', not 'noted' … the same class also touchespartial-index-probe.ts:28,40(whose comment now states the opposite of what it does) andcli db clean".err.message— dropped here.Related
#16019 · PR #16650 · #8931 / PR #9273 (the same envelope on the typed read exits, where no such operator record existed)