Skip to content

Import dry-run skips field-level validation: dryRun:true reports ok:1 for a row the same endpoint then rejects #3956

Description

@baozhoutao

Summary

POST /api/v1/data/:object/import runs field-level validation only on the real write, not on the dry run. The exact same request body with dryRun:true reports the row as valid; with dryRun:false it fails. The Console import wizard surfaces the dry run as "验证数据 / 导入前在服务端逐行校验", so users are told their file is clean and then watch the import drop every row.

Version: @objectstack/* 17.0.0-rc.0.

Reproduce

  1. Declare a number field with a bound:
penalty_amount: {type: 'number',label: '处罚金额',precision: 12,scale: 2,required: true,min: 0,max: 9999999.99}
  1. In the Console list view → 导入 → upload a CSV whose row violates the bound (处罚金额 = -500).
  2. On the preview step click 校验数据 (the dry run).
  3. Then click 导入 1 行 (the real write).

Actual

Dry run — POST /api/v1/data/os_tianshun_ehr_penalty_standard/import:

{"object":"os_tianshun_ehr_penalty_standard","dryRun":true,"writeMode":"insert",
"total":1,"ok":1,"errors":0,"created":1,"updated":0,"skipped":0,
"results":[{"row":1,"ok":true,"action":"created"}]}

UI shows 「全部 1 行均有效。」

Real write — same endpoint, same payload, only dryRun flipped:

{"object":"os_tianshun_ehr_penalty_standard","dryRun":false,"writeMode":"insert",
"total":1,"ok":0,"errors":1,"created":0,"updated":0,"skipped":0,
"results":[{"row":1,"ok":false,"action":"failed",
"error":"penalty_amount must be ≥ 0","code":"VALIDATION_FAILED"}]}

UI shows 「已导入 0 条 / 已跳过 1 条 · 第 1 行:penalty_amount must be ≥ 0」.

Note the dry run even claims created: 1.

Expected

The dry run should run the same validateRecord pass as the write path and report ok:0, errors:1 with the same per-row error. A dry run that does not validate is worse than no dry run — it converts "your file has a problem" into a false all-clear.

Scope

Not specific to min/max — the dry run appears to cover only mapping/lookup resolution (it does catch 申请部门: 找不到匹配 "X" 的记录 and required-lookup misses). Anything enforced by validateRecord (numeric range, string length, type checks) is invisible to it, so the same false all-clear should reproduce with e.g. maxLength.

Impact

Found while adding range guards to the settlement fields of a production MES app (25 objects). The import wizard is the primary bulk-data path during implementation; a green pre-check that doesn't predict the write outcome makes the whole pre-check step untrustworthy, and reviewers can't use it as acceptance evidence.

Related: the per-row error string is hardcoded English + API field name — filed separately.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions