[Drizzle] Improper Date parsing/validation for user signup (toISOString is not a function) #2060

Closed
opened 2026-03-13 09:23:32 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @neilsong on GitHub (Oct 2, 2025).

Originally assigned to: @ping-maxwell on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Use Drizzle with Postgres, define a user table with a timestamp column (follows from better auth cli)
  2. Configure auth with a 'date' typed additionalField on user
  3. Attempt signUp with the additionalField as follows:
await authClient.signUp.email({
        ...,
        dateField: new Date(),
});

Current vs. Expected behavior

Better Auth will error with toISOString is not a function when attempting to create the db user with the Drizzle adapter. This is because Drizzle expects a Date typed value when inserting for a timestamp column.

The Better Auth cli will generate the following Drizzle schema definition for the above additionalFields config as well:

export const user = pgTable("user", {
   ...,
  dateField: timestamp("date_field")
});

The additionalField parsing should be proper for Drizzle (convert to a Date object before insertion).

What version of Better Auth are you using?

1.3.24

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000",
    "release": "24.6.0",
    "cpuCount": 10,
    "cpuModel": "Apple M1 Pro",
    "totalMemory": "32.00 GB",
    "freeMemory": "0.58 GB"
  },
  "node": {
    "version": "v22.18.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.3"
  },
  "frameworks": null,
  "databases": null,
  "betterAuth": {
    "version": "Unknown",
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
  user: {
      additionalFields: {
        dateField: {
          type: "date",
          required: true,
        },
      }
  }
});

Additional context

Regression from 1.2.9 -> 1.3.24, unsure which version caused it.

For anyone facing this particular problem, for now, the easiest solution is to change your schema definition for the date field to:

dateField: timestamp("date_field", { mode: "string" }),

Will not require a migration as this just changes Drizzle's behavior before db insertion. With this approach, be careful when accessing the date field on any instance of the user: it will not be a Date instance as the types suggest, it will instead be the ISO string representation.

Originally created by @neilsong on GitHub (Oct 2, 2025). Originally assigned to: @ping-maxwell on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Use Drizzle with Postgres, define a user table with a `timestamp` column (follows from better auth cli) 2. Configure auth with a `'date'` typed additionalField on user 3. Attempt `signUp` with the additionalField as follows: ```ts await authClient.signUp.email({ ..., dateField: new Date(), }); ``` ### Current vs. Expected behavior Better Auth will error with `toISOString is not a function` when attempting to create the db user with the Drizzle adapter. This is because Drizzle expects a `Date` typed value when inserting for a `timestamp` column. The Better Auth cli will generate the following Drizzle schema definition for the above additionalFields config as well: ```ts export const user = pgTable("user", { ..., dateField: timestamp("date_field") }); ``` The additionalField parsing should be proper for Drizzle (convert to a Date object before insertion). ### What version of Better Auth are you using? 1.3.24 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000", "release": "24.6.0", "cpuCount": 10, "cpuModel": "Apple M1 Pro", "totalMemory": "32.00 GB", "freeMemory": "0.58 GB" }, "node": { "version": "v22.18.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.3" }, "frameworks": null, "databases": null, "betterAuth": { "version": "Unknown", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, user: { additionalFields: { dateField: { type: "date", required: true, }, } } }); ``` ### Additional context Regression from 1.2.9 -> 1.3.24, unsure which version caused it. For anyone facing this particular problem, for now, the easiest solution is to change your schema definition for the date field to: ```ts dateField: timestamp("date_field", { mode: "string" }), ``` Will not require a migration as this just changes Drizzle's behavior before db insertion. With this approach, be careful when accessing the date field on any instance of the user: it will not be a Date instance as the types suggest, it will instead be the ISO string representation.
GiteaMirror added the bug label 2026-03-13 09:23:32 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Oct 2, 2025):

Hi @neilsong! I'm Dosu and I’m helping the better-auth team.

This is a known issue with Better Auth and Drizzle: the error happens because Better Auth expects timestamp fields (including additionalFields of type "date") to be JavaScript Date objects, but Drizzle can return or accept strings if you use { mode: "string" } or if the schema/migration isn't set up to always provide Date objects. When a non-Date value is passed, calling .toISOString() fails, causing the error you see [source].

To avoid this, make sure your Drizzle schema for all timestamp fields—including any additionalFields of type "date"—always provides a real Date object. The recommended approach is to use .$defaultFn(() => new Date()) for all relevant fields, and for fields like updatedAt, add .$onUpdate(() => new Date()) [source]. Avoid using { mode: "string" } unless you are prepared to manually convert strings to Date objects before using them in Better Auth logic [source].

Recent changes in the Better Auth CLI switched generated timestamp fields to use .defaultNow() instead of .$defaultFn(() => new Date()), which may affect type consistency and could be related to the regression you noticed [source].

If you must use { mode: "string" }, you need to manually wrap string values in new Date() before passing them to any logic that expects a Date object [source]. There is no built-in support for this conversion in the Drizzle adapter as of now.

In summary: always use Date objects for timestamp fields in your Drizzle schema with Better Auth, and avoid { mode: "string" } unless you handle conversion yourself. This will prevent the toISOString is not a function error during user signup and other flows.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

@dosubot[bot] commented on GitHub (Oct 2, 2025): <!-- Greeting --> Hi @neilsong! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known issue with Better Auth and Drizzle: the error happens because Better Auth expects timestamp fields (including additionalFields of type "date") to be JavaScript Date objects, but Drizzle can return or accept strings if you use `{ mode: "string" }` or if the schema/migration isn't set up to always provide Date objects. When a non-Date value is passed, calling `.toISOString()` fails, causing the error you see [[source](https://github.com/better-auth/better-auth/issues/4434)]. To avoid this, make sure your Drizzle schema for all timestamp fields—including any additionalFields of type "date"—always provides a real Date object. The recommended approach is to use `.$defaultFn(() => new Date())` for all relevant fields, and for fields like `updatedAt`, add `.$onUpdate(() => new Date())` [[source](https://github.com/better-auth/better-auth/issues/4434)]. Avoid using `{ mode: "string" }` unless you are prepared to manually convert strings to Date objects before using them in Better Auth logic [[source](https://github.com/better-auth/better-auth/issues/1418)]. Recent changes in the Better Auth CLI switched generated timestamp fields to use `.defaultNow()` instead of `.$defaultFn(() => new Date())`, which may affect type consistency and could be related to the regression you noticed [[source](https://github.com/better-auth/better-auth/pull/3873)]. If you must use `{ mode: "string" }`, you need to manually wrap string values in `new Date()` before passing them to any logic that expects a Date object [[source](https://github.com/better-auth/better-auth/issues/4159)]. There is no built-in support for this conversion in the Drizzle adapter as of now. In summary: always use Date objects for timestamp fields in your Drizzle schema with Better Auth, and avoid `{ mode: "string" }` unless you handle conversion yourself. This will prevent the `toISOString is not a function` error during user signup and other flows. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/27a69db3-297a-4880-996e-b6df369a5c27?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/27a69db3-297a-4880-996e-b6df369a5c27?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/27a69db3-297a-4880-996e-b6df369a5c27?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/27a69db3-297a-4880-996e-b6df369a5c27?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/27a69db3-297a-4880-996e-b6df369a5c27?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/27a69db3-297a-4880-996e-b6df369a5c27?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/27a69db3-297a-4880-996e-b6df369a5c27?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/5032)
Author
Owner

@neilsong commented on GitHub (Oct 13, 2025):

Quick bump on this @ping-maxwell - not sure if this issue might have already been resolved by another pr

@neilsong commented on GitHub (Oct 13, 2025): Quick bump on this @ping-maxwell - not sure if this issue might have already been resolved by another pr
Author
Owner

@ping-maxwell commented on GitHub (Oct 14, 2025):

hmm? no I don't think so. Just a matter on waiting for PR review + merge.

@ping-maxwell commented on GitHub (Oct 14, 2025): hmm? no I don't think so. Just a matter on waiting for PR review + merge.
Author
Owner

@neilsong commented on GitHub (Nov 11, 2025):

Closed by #5042

@neilsong commented on GitHub (Nov 11, 2025): Closed by #5042
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2060