[GH-ISSUE #6482] Input validator saves the values as a json in the database on v1.4.0 and up #10529

Closed
opened 2026-04-13 06:44:04 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @Kiojeen on GitHub (Dec 3, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6482

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. add additional fields to your user in configs
  2. add something like a bio field
  3. add validation to the bio
 user: {
    additionalFields: {
      bio: {
        type: "string",
        required: false,
        defaultValue: "",
        validator: {
          input: z.string().max(500),
          output: z.string().max(500),
        },
      },
    },
  }
  1. save a bio in the user's account

Current vs. Expected behavior

I was expecting the bio (or any other field with validator) to be saved as is but it saves as a json:

{"value":"Hi, this bio is supposed to be a string!"}

i tried going back to v1.3.28 and it worked perfectly fine. but once i updated to 1.4.0 and up to 1.4.5 (latest) this issue happened.

it happens whenever i use the validator, otherwise it works fine when no validator is used

What version of Better Auth are you using?

1.4.5

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Pro",
    "release": "10.0.26100",
    "cpuCount": 12,
    "cpuModel": "AMD Ryzen 5 5600G with Radeon Graphics         ",
    "totalMemory": "15.37 GB",
    "freeMemory": "0.56 GB"
  },
  "node": {
    "version": "v22.18.0",
    "env": "development"
  },
  "packageManager": {
    "name": "pnpm",
    "version": "10.17.1"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "16.0.1"
    },
    {
      "name": "react",
      "version": "19.2.0"
    }
  ],
  "databases": [
    {
      "name": "postgres",
      "version": "^3.4.7"
    },
    {
      "name": "drizzle",
      "version": "^0.44.6"
    },
    {
      "name": "@neondatabase/serverless",
      "version": "^1.0.2"
    }
  ],
  "betterAuth": {
    "version": "^1.4.5",
    "config": null
  }
}

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

Backend

Auth config (if applicable)

import { env } from "@/env";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
import { admin } from "better-auth/plugins";
import { z } from "zod";

import { db } from "@/server/db";
import { schema } from "@/server/db/schema";

export const auth = betterAuth({
  appName: "appName",
  database: drizzleAdapter(db, {
    provider: "pg", // or "pg" or "mysql"
    schema: schema,
  }),

  ...(env.NODE_ENV === "development" && {
    trustedOrigins: ["https://192.168.4.100:3000"],
  }),

  user: {
    additionalFields: {
      countryIsoCode: {
        type: "string",
        required: false,
      },
      phoneNumber: {
        type: "string",
        required: false,
      },
      bio: {
        type: "string",
        required: false,
        defaultValue: "",
        validator: {
          input: z.string().max(500),
          output: z.string().max(500),
        },
      },
    },
  },
  advanced: {
    ...(env.NODE_ENV === "production" && {
      defaultCookieAttributes: {
        httpOnly: true,
        secure: true,
      },
    }),
    cookiePrefix: "myapp",
  },
  logger: {
    disabled: false,
    disableColors: false,
    level: "error",
    log: (level, message, ...args) => {
      // Custom logging implementation
      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
      console.log(`[${level}] ${message}`, ...args);
    },
  },
  telemetry: {
    debug: true,
  },
  emailAndPassword: {
    enabled: true,
    autoSignIn: true,
    minPasswordLength: 8,
    maxPasswordLength: 128,
  },
  plugins: [
    admin({
      defaultRole: "user",
      adminRoles: ["admin"],
    }),
    nextCookies(), // make sure this is the last plugin in the array
  ],
});

export type Session = typeof auth.$Infer.Session;

Additional context

No response

Originally created by @Kiojeen on GitHub (Dec 3, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6482 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. add additional fields to your user in configs 2. add something like a bio field 3. add validation to the bio ```javascript user: { additionalFields: { bio: { type: "string", required: false, defaultValue: "", validator: { input: z.string().max(500), output: z.string().max(500), }, }, }, } ``` 4. save a bio in the user's account ### Current vs. Expected behavior I was expecting the bio (or any other field with validator) to be saved as is but it saves as a json: ```json {"value":"Hi, this bio is supposed to be a string!"} ``` i tried going back to v1.3.28 and it worked perfectly fine. but once i updated to 1.4.0 and up to 1.4.5 (latest) this issue happened. it happens whenever i use the validator, otherwise it works fine when no validator is used ### What version of Better Auth are you using? 1.4.5 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Pro", "release": "10.0.26100", "cpuCount": 12, "cpuModel": "AMD Ryzen 5 5600G with Radeon Graphics ", "totalMemory": "15.37 GB", "freeMemory": "0.56 GB" }, "node": { "version": "v22.18.0", "env": "development" }, "packageManager": { "name": "pnpm", "version": "10.17.1" }, "frameworks": [ { "name": "next", "version": "16.0.1" }, { "name": "react", "version": "19.2.0" } ], "databases": [ { "name": "postgres", "version": "^3.4.7" }, { "name": "drizzle", "version": "^0.44.6" }, { "name": "@neondatabase/serverless", "version": "^1.0.2" } ], "betterAuth": { "version": "^1.4.5", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { env } from "@/env"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { nextCookies } from "better-auth/next-js"; import { admin } from "better-auth/plugins"; import { z } from "zod"; import { db } from "@/server/db"; import { schema } from "@/server/db/schema"; export const auth = betterAuth({ appName: "appName", database: drizzleAdapter(db, { provider: "pg", // or "pg" or "mysql" schema: schema, }), ...(env.NODE_ENV === "development" && { trustedOrigins: ["https://192.168.4.100:3000"], }), user: { additionalFields: { countryIsoCode: { type: "string", required: false, }, phoneNumber: { type: "string", required: false, }, bio: { type: "string", required: false, defaultValue: "", validator: { input: z.string().max(500), output: z.string().max(500), }, }, }, }, advanced: { ...(env.NODE_ENV === "production" && { defaultCookieAttributes: { httpOnly: true, secure: true, }, }), cookiePrefix: "myapp", }, logger: { disabled: false, disableColors: false, level: "error", log: (level, message, ...args) => { // Custom logging implementation // eslint-disable-next-line @typescript-eslint/no-unsafe-argument console.log(`[${level}] ${message}`, ...args); }, }, telemetry: { debug: true, }, emailAndPassword: { enabled: true, autoSignIn: true, minPasswordLength: 8, maxPasswordLength: 128, }, plugins: [ admin({ defaultRole: "user", adminRoles: ["admin"], }), nextCookies(), // make sure this is the last plugin in the array ], }); export type Session = typeof auth.$Infer.Session; ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-13 06:44:04 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 3, 2025):

Thanks for reporting this! It appears that when using a validator for additional fields (like your bio), the current implementation in versions 1.4.0 and up wraps the validated value in an object (e.g., { value: "..." }) rather than storing the plain string as before. This behavior wasn’t observed in version 1.3.28, so it seems like a change introduced in the newer versions.

As a next step, you might try one of the following troubleshooting approaches:
• Temporarily remove or disable the validator for the bio field to confirm that the plain string is saved (this helps isolate the issue to the validator logic).
• Adjust your data retrieval logic to extract the actual value from the JSON object if you must use the validator.
• Check if there are any migration notes or documentation updates regarding changes in input validation behavior between 1.3.x and 1.4.x.

Our team is aware of this issue, and we’re looking into a more consistent solution so that validated fields are stored as their raw data type.

Tag @better-auth-agent if you would like an answer from the Agent. Could you let us know if these troubleshooting steps help or if you have additional questions?

If you need more help, tag @Skyvern in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3604508501 --> @better-auth-agent[bot] commented on GitHub (Dec 3, 2025): Thanks for reporting this! It appears that when using a validator for additional fields (like your bio), the current implementation in versions 1.4.0 and up wraps the validated value in an object (e.g., { value: "..." }) rather than storing the plain string as before. This behavior wasn’t observed in version 1.3.28, so it seems like a change introduced in the newer versions. As a next step, you might try one of the following troubleshooting approaches: • Temporarily remove or disable the validator for the bio field to confirm that the plain string is saved (this helps isolate the issue to the validator logic). • Adjust your data retrieval logic to extract the actual value from the JSON object if you must use the validator. • Check if there are any migration notes or documentation updates regarding changes in input validation behavior between 1.3.x and 1.4.x. Our team is aware of this issue, and we’re looking into a more consistent solution so that validated fields are stored as their raw data type. Tag @better-auth-agent if you would like an answer from the Agent. Could you let us know if these troubleshooting steps help or if you have additional questions? _If you need more help, tag @Skyvern in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@GautamBytes commented on GitHub (Dec 3, 2025):

Looking into it!!

<!-- gh-comment-id:3605222953 --> @GautamBytes commented on GitHub (Dec 3, 2025): Looking into it!!
Author
Owner

@Kiojeen commented on GitHub (Dec 3, 2025):

Looking into it!!

Thanks!

<!-- gh-comment-id:3607029711 --> @Kiojeen commented on GitHub (Dec 3, 2025): > Looking into it!! Thanks!
Author
Owner

@kernoeb commented on GitHub (Dec 6, 2025):

Hello!
I tried the last beta version of better-auth, but i still have a regression in my case

blocklist: {
  type: 'string[]',
  validator: { input: z.array(z.string()).optional() },
},

i have a string[] type :

in 1.3 -> it works properly
in 1.4.0 - 1.4.6-beta.2 -> same issue as Kiojeen { value: xxx }
in 1.4.6-beta.3 -> i get a string "[xxx, xxxx]" instead of an array and value.map is not a function.

<!-- gh-comment-id:3620716288 --> @kernoeb commented on GitHub (Dec 6, 2025): Hello! I tried the last beta version of better-auth, but i still have a regression in my case ```ts blocklist: { type: 'string[]', validator: { input: z.array(z.string()).optional() }, }, ``` i have a `string[]` type : in `1.3` -> it works properly in `1.4.0` - `1.4.6-beta.2` -> same issue as Kiojeen `{ value: xxx }` in `1.4.6-beta.3` -> i get a `string` "[xxx, xxxx]" instead of an array and `value.map is not a function.`
Author
Owner

@DibyodyutiMondal commented on GitHub (Dec 9, 2025):

i think the issue with string serialization is related to
https://github.com/better-auth/better-auth/issues/6552

<!-- gh-comment-id:3633671216 --> @DibyodyutiMondal commented on GitHub (Dec 9, 2025): i think the issue with string serialization is related to https://github.com/better-auth/better-auth/issues/6552
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10529