Skip to content

ZenStack 3.6: strict Date input validator rejects ISO strings (regression vs 3.4 / Prisma) #2631

@erwan-joly

Description

@erwan-joly

Background

After upgrading from @zenstackhq/orm@3.4.6@zenstackhq/orm@3.6.4, code paths that previously passed an ISO string to a DateTime field now fail with:

Validation error:
  Invalid input: expected object, received array at "data.<relation>.createMany.data"
  Invalid ISO datetime at "data.<relation>.createMany.data[0].<field>"
  Invalid ISO date at "data.<relation>.createMany.data[0].<field>"
  Invalid input: expected date, received string at "data.<relation>.createMany.data[0].<field>"

  caused by: ZodError
    at InputValidator.validate (.../validator.ts:294)
    at InputValidator.validateCreateArgs (.../validator.ts:80)
    at CreateOperationHandler.handle (.../create.ts:13)

The affected fields are backed by @db.Time(6) / @db.Date. The inputs were valid ISO 8601 strings (e.g. "09:00:00", "2024-04-01", or "2024-04-01T00:00:00.000Z").

Minimal repro

model Parent {
  id       String  @id @default(uuid())
  children Child[]
}

model Child {
  id       String   @id @default(uuid())
  parentId String
  open     DateTime @db.Time(6)
  parent   Parent   @relation(fields: [parentId], references: [id])
}
// 3.4.6 — works (Prisma coerces the string → Date)
// 3.6.4 — throws (zod union rejects all three branches)
await db.parent.create({
  data: {
    children: {
      createMany: {
        data: [{ open: "09:00:00" }],
      },
    },
  },
});

What I think is happening

In 3.6.x the input layer builds a Zod schema where DateTime resolves to a union roughly equivalent to z.union([z.iso.datetime(), z.iso.date(), z.date()]). None of the three branches match a bare @db.Time value like "09:00:00", so the union rejects.

3.4.x went through a Prisma-compatible coercion layer that accepted ISO strings and converted them to Date for the engine. The new behavior is technically more correct (a DateTime field semantically expects a Date), but it's a breaking change I couldn't find in the 3.5 / 3.6 release notes.

Related to #2590, which fixed the read side of @db.Time (raw strings being silently returned instead of Dates and crashing downstream .getUTCFullYear() calls). The input side now needs every caller updated.

Suggested resolution

Pick one:

  1. Restore Prisma-compatible coercion — accept ISO strings on DateTime inputs and convert to Date. Matches Prisma's longstanding behavior.
  2. Add a config option, e.g. ClientOptions.strictDateInputs: boolean (default false to match 3.4.x). Lets users opt into the strict mode while keeping backward compat by default.
  3. Keep the strict behavior but call it out as a breaking change in the release notes with a migration guide entry (recommended fix: new Date(isoString) or equivalent).

Filing this neutrally — could go either way. Thanks for ZenStack!

Versions

  • @zenstackhq/orm: 3.6.4 (was 3.4.6 working)
  • @zenstackhq/cli: 3.6.4
  • prisma: 7.8.0
  • node: 22.x

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions