Skip to content

adapter-pg: timestamps with extended (>4-digit) years silently deserialize to Invalid Date #30151

Description

@ChamPro

Package and version

@prisma/adapter-pg@7.8.0 (with @prisma/client@7.8.0, prisma CLI 7.9.1)

What happened?

Bug description

@prisma/adapter-pg fails to deserialize Postgres timestamps whose year has more
than 4 digits. Instead of throwing, it silently returns an Invalid Date — a Date
object whose getTime() is NaN. Because the TypeScript type is still Date, the
value passes type checking and flows downstream until something calls .toISOString(),
at which point the app crashes with RangeError: Invalid time value far from the
actual cause.

Once such a row exists, every read of that row crashes, making the affected page
unrecoverable through the UI.

Root cause

normalize_timestamp in the pg adapter converts the Postgres wire format to something
new Date() can parse:

function normalize_timestamp(time) {
  return `${time.replace(" ", "T")}
}

ISO 8601 requires expanded years (more than 4 digits) to carry an explicit sign.
normalize_timestamp replaces the sp offset, but does not
add the required +, so V8's strict ISO parser rejects the result:

new Date("202609-02-05T05:00:00+00:00")   // Invalid Date
new Date("+202609-02-05T05:00:00+00:00:00.000Z  ✅
new Date("2026-09-02T05:00:00+00:00")     // 2026-09-02T05:00:00.000Z     ✅ (4-digit unaffected)

The value itself is well within JS Date range (which extends to year 275760)  this
is purely a string-formatting probloverflow.






### What did you expect to happen?

Expected behavior

Either:
- Preferred: prepend + for expanded years so the timestamp round-trips correctly, or
- Throw an explicit, descriptive erestamp: <value>) so the
  failure surfaces at the adapter boundary instead of silently producing an invalid
  Date that crashes elsewhere

Silently returning Invalid Date is ions: it type-checks as
Date, propagates freely, and surfaces as a RangeError in unrelated code.

### Minimal reproduction

How to reproduce

1. Use @prisma/adapter-pg with a Po
2. Insert a row with a DateTime field whose year has more than 4 digits, e.g.
   202609-02-05. This is easy to prput type="date"> value
   with a typo, coerced via new Date(string) (or z.coerce.date()), is accepted by
   JavaScript's lenient legacy parsithout error
3. Read the row back with Prisma Client
4. The DateTime field is an Invalid
5. Any .toISOString() / .toJSON() / JSON.stringify() on it throws
   RangeError: Invalid time value



Control experiment

Querying the same row with the bare pg driver works correctly:

column type: timestamp without time zone, precision 3

bare pg  [202609-02-05 05:00:00]  instanceof Date = true   getTime() = 6331558356000000
bare pg  [2026-09-02 05:00:00]    itTime() = 1788339600000

// the same wire values, put throug:
normalize_timestamp("202609-02-05 05:00:00")
  -> "202609-02-05T05:00:00+00:00" id Date (getTime() = NaN)
normalize_timestamp("2026-09-02 05:00:00")
  -> "2026-09-02T05:00:00+00:00"   09-02T05:00:00.000Z

So this is specific to the adapter'to PostgreSQL or
node-postgres.

### Environment

- prisma / @prisma/client: 7.9.1 (CLI) / 7.8.0 (@prisma/client)
- @prisma/adapter-pg: 7.8.0
- Node.js: 20.19.5
- PostgreSQL: 17.6 (Supabase manage
- OS: macOS 26.2 (arm64)
- Note: CLI at 7.9.1, client and adapter at 7.8.0.

### Additional context

Related issues

This looks like another instance of a broader input-robustness gap in
normalize_timestamp, which assumes -formed timestamp string:

- #29190  normalize_timestamp calllable DateTime,
  throwing a TypeError
- #26786 / #28629  @db.Timestamptztly under driver adapters
  when the database timezone is not UTC (also does not reproduce without the adapter)

Metadata

Metadata

Assignees

No one assigned

    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