Summary
The generic data API silently accepts payload fields that are not declared on the object, passing them straight through to the driver. On SQLite this surfaces as a raw table X has no column named <field> error; the caller gets no field-level feedback. Mature low-code platforms (e.g. Salesforce INVALID_FIELD) reject unknown fields at the API layer — the schema is the contract.
Repro
POST /api/v1/data/sys_team with body { "name": "x", "label": "x" } (label is not a field on sys_team).
Before the error-mapping safety net (fix/rest-map-schema-errors) this returned 500 DATABASE_ERROR; with it, a 400 INVALID_FIELD. But that is a last-resort string-match on the driver error — the real fix is to reject the unknown field before building SQL.
Root cause
packages/objectql/src/validation/record-validator.ts validateRecord() iterates over declared schema fields, never over payload keys:
// insert mode
for (const [name, def] of Object.entries(fields)) { ... } // schema-driven only
Keys present in data but absent from fields are never examined → they survive into the driver create()/update() call.
Proposed change
In validateRecord, after the declared-field walk, iterate Object.keys(data) and push a { code: unknown_field } error for any key that is not a schema field and not an allow-listed control key.\n\n### Open design points\n- Allow-list for legitimate non-column keys: $-prefixed control keys, nested related-record writes, computed/formula display fields the UI may echo back, system-injected columns. Need to enumerate before enforcing.\n- Rollout: hard-enforce now vs. log-then-enforce (one release warns, next rejects) to avoid 400-ing clients that currently send extras. Requires a quick audit of what @object-ui/console + the os CLI actually POST.\n- Applies to both insert and update (PATCH).\n\n## Why this matters long-term\nFixes the entire "unknown field" class at the correct layer, for all objects, and makes the API self-documenting — instead of relying on a dialect-specific driver-error regex in rest-server.ts mapDataError().\n\n## Related\n- Safety net already landed: branch fix/rest-map-schema-errors (PR pending) — mapDataError maps unknown-column/not-null → 4xx.\n- Pairs with the managedBy enforcement + provenance issues (linked below).\n\n_Found running cloud LOCAL-E2E-CHECKLIST B7 (per-env data API CRUD)._
Summary
The generic data API silently accepts payload fields that are not declared on the object, passing them straight through to the driver. On SQLite this surfaces as a raw
table X has no column named <field>error; the caller gets no field-level feedback. Mature low-code platforms (e.g. SalesforceINVALID_FIELD) reject unknown fields at the API layer — the schema is the contract.Repro
POST /api/v1/data/sys_teamwith body{ "name": "x", "label": "x" }(labelis not a field onsys_team).Before the error-mapping safety net (fix/rest-map-schema-errors) this returned
500 DATABASE_ERROR; with it, a400 INVALID_FIELD. But that is a last-resort string-match on the driver error — the real fix is to reject the unknown field before building SQL.Root cause
packages/objectql/src/validation/record-validator.tsvalidateRecord()iterates over declared schema fields, never over payload keys:Keys present in
databut absent fromfieldsare never examined → they survive into the drivercreate()/update()call.Proposed change
In
validateRecord, after the declared-field walk, iterateObject.keys(data)and push a{ code: unknown_field }error for any key that is not a schema field and not an allow-listed control key.\n\n### Open design points\n- Allow-list for legitimate non-column keys:$-prefixed control keys, nested related-record writes, computed/formula display fields the UI may echo back, system-injected columns. Need to enumerate before enforcing.\n- Rollout: hard-enforce now vs. log-then-enforce (one release warns, next rejects) to avoid 400-ing clients that currently send extras. Requires a quick audit of what@object-ui/console+ theosCLI actually POST.\n- Applies to both insert and update (PATCH).\n\n## Why this matters long-term\nFixes the entire "unknown field" class at the correct layer, for all objects, and makes the API self-documenting — instead of relying on a dialect-specific driver-error regex inrest-server.tsmapDataError().\n\n## Related\n- Safety net already landed: branchfix/rest-map-schema-errors(PR pending) —mapDataErrormaps unknown-column/not-null → 4xx.\n- Pairs with themanagedByenforcement + provenance issues (linked below).\n\n_Found running cloudLOCAL-E2E-CHECKLISTB7 (per-env data API CRUD)._