fix(rest): map schema-mismatch & not-null driver errors to structured 4xx#1594
Merged
Conversation
… 4xx
`mapDataError` collapsed any SQL-looking driver error into a generic
500 `DATABASE_ERROR`, so a bad write payload — e.g. `POST /data/sys_team`
with an unknown `label` field, or omitting the required `organization_id`
— leaked a 500 instead of a fixable 4xx. (Found running LOCAL-E2E-CHECKLIST
B7: per-env data API CRUD.)
Add two structured branches before the unknown-object / SQL-leak fallbacks:
- unknown column → 400 INVALID_FIELD { field } (SQLite "has no column
named" / "no such column"; Postgres 'column "c" of relation ... does not
exist'; MySQL "Unknown column 'c'"). Placed before the unknown-object
branch so the Postgres phrasing isn't mis-mapped to 404 object_not_found.
- not-null → 400 VALIDATION_FAILED { fields:[{required}] } (SQLite
"NOT NULL constraint failed: t.c"; Postgres "null value in column";
MySQL "Column 'c' cannot be null").
Genuine driver faults (e.g. SQLITE_IOERR) and unique violations are
unchanged (500 DATABASE_ERROR / 409 UNIQUE_VIOLATION). This is a
last-resort safety net; the durable fix is upstream validation
(unknown-field rejection + provenance-aware required checks) — tracked
separately.
Export `mapDataError` (package-internal; not added to index) + 8 tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
mapDataErrorcollapsed any SQL-looking driver error into a generic500 DATABASE_ERROR. A bad write payload to the data API therefore leaked a 500 instead of a fixable 4xx — e.g.POST /api/v1/data/sys_teamwith an unknownlabelfield, or omitting requiredorganization_id.Adds two structured branches before the unknown-object / SQL-leak fallbacks:
has no column named/no such column/column … of relation … does not exist/Unknown column)500 DATABASE_ERROR400 INVALID_FIELD { field, object }NOT NULL constraint failed/null value in column/cannot be null)500 DATABASE_ERROR400 VALIDATION_FAILED { fields:[{required}] }The unknown-column branch is placed before the unknown-object branch so Postgres
column "x" of relation "y" does not existisn't mis-mapped to404 object_not_found. Genuine driver faults (SQLITE_IOERR) still → 500; unique violations still → 409 (unchanged).Why
Found running cloud
LOCAL-E2E-CHECKLISTB7 (per-env data API CRUD). This is a last-resort safety net — the durable fixes are upstream validation, tracked in #1590 (reject unknown fields), #1591 (enforcemanagedBy), #1592 (provenance-aware required checks). This PR closes the 500-leak symptom now.Test
mapDataError(SQLite/Postgres/MySQL phrasings, both error classes, plus genuine-leak-still-500 and unique-still-409 guards).@objectstack/restsuite: 86/86 green.tsupbuild clean.mapDataErrorexported package-internally (not added toindex.ts) for testability.Closes none directly; unblocks B7.
🤖 Generated with Claude Code