fix(rest): validate required fields in import dry-run to match the real insert#2839
Merged
Conversation
…al insert The bulk-import dry run (`POST /data/:object/import`, dryRun:true) only ran cell coercion, then reported every coercible CREATE row as ok — so a row missing a required NOT-NULL field with no default was green-lit, then died on the real insert with `NOT NULL constraint failed` (live: mx1n_member.status). The ImportWizard shows the dry-run result, so it promised imports that then failed. Add a required-field pre-check to the shared import runner (CREATE rows only), mirroring the engine's insert-time validation (objectql record-validator.ts + applyFieldDefaults): a required field is unsatisfied only when it has no value AND no default; system/readonly/autonumber and engine-owned lifecycle columns are exempt. Carried on ExportFieldMeta (required/system/readonly/hasDefault), populated by buildFieldMetaMap. Applied to both dry-run and real paths so they stay identical and the real insert returns a readable `<field> is required` instead of a raw driver error; skipped when runAutomations is set (a beforeInsert hook may populate the field).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 8 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…-field validation
os-zhuang
marked this pull request as ready for review
July 11, 2026 13:56
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.
Problem
POST /data/:object/importwithdryRun:truereports success for rows that then FAIL the real insert on NOT NULL / required-field constraints. The dry-run branch inimport-runner.tsonly runs cell coercion (coerceRow), then marks every coercible CREATE rowok— it never checks that required fields have a value. The real insert goes through the engine, where a required (⇒ NOT NULL) column with no default and no value is rejected.Live-observed (2026-07-11), AI-built object
mx1n_member(requiredmember_name;status— a selectactive/frozen/lost_contact/archived, no default):dryRun:true→{total:5, ok:5, errors:0}(says all 5 will succeed)dryRun:false(same rows, missingstatus) →{ok:0, errors:5}, eachNOT NULL constraint failed: mx1n_member.statusThe ImportWizard (objectui) shows the dry-run result, so it promised imports that then failed.
Fix
A required-field pre-check in the shared import runner (
runImport), applied to CREATE rows, mirroring the engine's insert-time validation (objectql/record-validator.ts+applyFieldDefaults):system/readonly/autonumberand the engine-owned lifecycle columns (id,created_at, …) are exempt — exactly the engine's own exemptions.ExportFieldMetagainsrequired/system/readonly/hasDefault, populated bybuildFieldMetaMapfrom the object schema (unused by the export path).firstMissingRequiredField(data, metaMap)inimport-coerce.ts.status is requiredinstead of a raw driver error. Skipped whenrunAutomationsis set — abeforeInserthook may legitimately populate a required field, so we defer to the engine's own validation there.Tests
import-integration.test.ts(real engine + protocol) gains amemberfixture (requiredmember_name; required-no-defaultstatus; required-but-defaultedtier) and cases:code:'required'; the complete row still succeeds;Full
restimport suite green (44/44 locally against the previously-pinned SHA; branch rebased onto currentmain, andexport-format.tscleanly merged with the xlsx-color change #2761).Companion (cloud)
objectstack-ai/cloud#807 (merged) gives AI-built objects a sensible default for required select fields — the root-cause fix for AI-built objects. This PR is the general safety net that makes the dry run honest for every object, including required text fields that can't be auto-defaulted. Once merged, cloud's
.framework-shashould be bumped to pick it up.🤖 Generated with Claude Code
https://claude.ai/code/session_01P5MRtrxWenRExebx2WrnFt
Generated by Claude Code