Skip to content

Zod 4 CSV upload reports a generic error for a RECORD_ARRAY key not in the schema instead of naming the key #1646

Open

Description

@joshunrau

On the Zod 4 CSV upload path, a RECORD_ARRAY(...) cell that names a key the schema does not define crashes with a TypeError instead of producing a useful error. The key comes from user data and is used to index the schema's dimensions with a non-null assertion. The lookup returns undefined, and interpretZodConvertResult then reads .isOptional/.typeName off it. The TypeError is not an UploadError, so processInstrumentCSV reports only "Error parsing CSV", with no column, row or key, and the user has no clue that a typo in a record key is the cause. (The Zod 3 path iterates the schema's keys instead, so it never reaches this crash.)

Where

apps/web/src/utils/upload.ts:753-755 (Zod4.interpretZodConvertResult, 'array' case):

return mapValues(parsedRecord, (value, key): unknown =>
  interpretZodConvertResult((convertResult.innerType as ObjectZodConvertResult).dimensions[key]!, value)
);

The generic fallback is at upload.ts:952-959.

Reproduce

Use a Zod 4 form instrument with validationSchema: z.object({ items: z.array(z.object({ name: z.string() })) }). Upload:

subjectID,date,items
subject1,2024-01-01,RECORD_ARRAY(unknown:a)
  • Actual: "Error parsing CSV". The console shows TypeError: Cannot read properties of undefined.
  • Expected: an UploadError that names the unknown key, for example "Unexpected key 'unknown' in RECORD_ARRAY at column name: 'items' and row number '1'".

Tests

apps/web/src/utils/__tests__/upload.test.ts, test 'should fall back to a generic error for a record key outside the schema, rather than naming the key' (under Zod4 › processInstrumentCSV). When fixing, rename it and change the expected rejection from 'Error parsing CSV' to the new message that names the key.

Suggested fix

Look up dimensions[key] without the assertion, and throw an UploadError naming the key when it is undefined. The existing catch then adds the column and row.

Found while raising unit test coverage in #1632.

Activity

  1. added
    BugType: existing behavior is wrong
    Priority: LowNice to have, cosmetic or speculative
    Difficulty: LowIsolated change, about 2 hours or less
    Area: Webapps/web (clinician-facing React SPA)
    Good First IssueWell-scoped, low-risk and self-contained; a good entry point for a new contributor
    on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: Webapps/web (clinician-facing React SPA)BugType: existing behavior is wrongDifficulty: LowIsolated change, about 2 hours or lessGood First IssueWell-scoped, low-risk and self-contained; a good entry point for a new contributorPriority: LowNice to have, cosmetic or speculative

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions