You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Data API: reject unknown payload fields (validateRecord ignores keys not in schema) #1590
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.tsvalidateRecord() iterates over declared schema fields, never over payload keys:
// insert modefor(const[name,def]ofObject.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.tsmapDataError().\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)._
Closing as deferred (startup-stage prioritization). Rationale:
No live data-integrity bug. An unknown field doesn't get silently written — the driver rejects the whole insert (no column named X). And the worst symptom (500 DATABASE_ERROR) is already mapped to a clean 400 INVALID_FIELD by the mapDataError safety net. So the user-facing pain is already handled.
The "proper layer" fix is API-hygiene polish with real back-compat cost — it would 400 any client (incl. our own console/CLI echoing computed/display fields) currently sending extras, and the author's own notes call for an allow-list audit + log-then-enforce rollout.
At current stage, premature input-strictness is net friction, not safety.
Revisit at GA / enterprise hardening, or when a concrete integration demands strict field validation — at which point do it with the audit + staged rollout. The metadata-honoring causes for the related set are partly addressed (#1592 silent-NULL fixed).
Activity
xuyushun441-sys commentedon Jun 5, 2026
Related set — three rungs of "the data API must honor object metadata before hitting the DB", surfaced together by
LOCAL-E2E-CHECKLISTB7:managedBy(who owns writes)organization_id)Landed as the error-mapping safety net: branch
fix/rest-map-schema-errors(maps the symptoms to 4xx; these issues are the causes).os-zhuang commentedon Jun 15, 2026
Closing as deferred (startup-stage prioritization). Rationale:
no column named X). And the worst symptom (500 DATABASE_ERROR) is already mapped to a clean400 INVALID_FIELDby themapDataErrorsafety net. So the user-facing pain is already handled.Revisit at GA / enterprise hardening, or when a concrete integration demands strict field validation — at which point do it with the audit + staged rollout. The metadata-honoring causes for the related set are partly addressed (#1592 silent-NULL fixed).