Found while implementing #8086 (PR #8130), which applies this predicate at the direct-mount package door. Measured, not inferred. Filed unassigned; nobody is on it.
The gap
looksLikeInternalErrorLeak (packages/types/src/error-leak.ts) is the shared "does this message leak server internals?" heuristic. Its keyword set is:
sqlite_ · sqlstate · startsWith("insert into ") · startsWith("update ")
startsWith("select ") · startsWith("delete from ") · constraint failed
unique constraint · foreign key
None of those matches Postgres's canonical missing-relation phrasing. Measured against the shipping predicate:
true "SQLITE_ERROR: no such table: sys_metadata"
false "relation \"sys_metadata\" does not exist"
true "UNIQUE constraint failed: sys_metadata.name"
false "Failed to delete customization overlay: relation \"sys_metadata\" does not exist"
true "SQLSTATE 08006: connection failure"
So the SQLite phrasing of a missing table is withheld and the Postgres phrasing of the same condition is disclosed, naming a physical table, from every boundary that applies the predicate — HttpDispatcher.error (#3867) and the direct-mount package door (#8086) among them. The one seam that is NOT affected is rest-server.ts's resolveErrorResponse band, which withholds every 5xx regardless of the predicate (#5437) — which is why rest-5xx-message-sanitization.test.ts has a green "Postgres phrasing is withheld too" case while the predicate itself returns false for that string. That case pins the seam's behaviour, not the predicate's, and reading it as the latter is the trap this issue exists to name.
Pinned as a live case in packages/rest/src/package-door-5xx-message-sanitization.test.ts (the residual case, added by PR #8130), which goes red the day this is fixed.
Why not "just add the keyword"
That is one option, and it is the cheapest, but it is worth deciding rather than reflexing — the predicate's own module note already argues against growing it:
Deliberately a heuristic over the message, not a driver taxonomy … Teaching the heuristic to recognise [read-scope-sql] would have been more message sniffing, which is the mechanism #5352/#5367 exist to remove.
That was written when #5811 added declaresServerFault alongside it, keying on the producer's declaration rather than its phrasing. Each new dialect string is one more entry in a list that is unbounded by construction — Postgres alone has relation … does not exist, column … does not exist, permission denied for table …, and MySQL/MSSQL/Oracle each phrase all of it differently. Every one of them is a leak the current set misses, and the list can only ever be as complete as the dialects someone has met.
Options, briefly:
A and C are not exclusive; A is a reasonable interim while C is scoped, the same shape #8086 settled on for its own door.
Note for triage
I could not find an existing card for #8086's option C ("metadata-protocol stops interpolating driver text into client-facing messages; the raw text goes to logs only"). #8086's PM ruling records it as the direction and says it "needs a producer-by-producer sweep, which is its own card", but no such issue appears in a search. If it was never filed, this issue and #8131 are both arguments for it, and all three probably want to be read together.
Found while implementing #8086 (PR #8130), which applies this predicate at the direct-mount package door. Measured, not inferred. Filed unassigned; nobody is on it.
The gap
looksLikeInternalErrorLeak(packages/types/src/error-leak.ts) is the shared "does this message leak server internals?" heuristic. Its keyword set is:None of those matches Postgres's canonical missing-relation phrasing. Measured against the shipping predicate:
So the SQLite phrasing of a missing table is withheld and the Postgres phrasing of the same condition is disclosed, naming a physical table, from every boundary that applies the predicate —
HttpDispatcher.error(#3867) and the direct-mount package door (#8086) among them. The one seam that is NOT affected isrest-server.ts'sresolveErrorResponseband, which withholds every 5xx regardless of the predicate (#5437) — which is whyrest-5xx-message-sanitization.test.tshas a green "Postgres phrasing is withheld too" case while the predicate itself returns false for that string. That case pins the seam's behaviour, not the predicate's, and reading it as the latter is the trap this issue exists to name.Pinned as a live case in
packages/rest/src/package-door-5xx-message-sanitization.test.ts(the residual case, added by PR #8130), which goes red the day this is fixed.Why not "just add the keyword"
That is one option, and it is the cheapest, but it is worth deciding rather than reflexing — the predicate's own module note already argues against growing it:
That was written when #5811 added
declaresServerFaultalongside it, keying on the producer's declaration rather than its phrasing. Each new dialect string is one more entry in a list that is unbounded by construction — Postgres alone hasrelation … does not exist,column … does not exist,permission denied for table …, and MySQL/MSSQL/Oracle each phrase all of it differently. Every one of them is a leak the current set misses, and the list can only ever be as complete as the dialects someone has met.Options, briefly:
declaresServerFaultwhere the producer declares. Already exists (/analytics/query仍把 RLS 策略字段名回显给调用方 —— read-scope 拒收的泄漏在姐妹面上没堵,#5367 只堵了 dataset 路由 #5811) for exactly the messages a phrasing test cannot see. Does not help a bareErrorfrom a driver, which declares nothing — and that is precisely the case here.A and C are not exclusive; A is a reasonable interim while C is scoped, the same shape #8086 settled on for its own door.
Note for triage
I could not find an existing card for #8086's option C ("
metadata-protocolstops interpolating driver text into client-facing messages; the raw text goes to logs only"). #8086's PM ruling records it as the direction and says it "needs a producer-by-producer sweep, which is its own card", but no such issue appears in a search. If it was never filed, this issue and #8131 are both arguments for it, and all three probably want to be read together.