[GH-ISSUE #7440] additionalFields with string[] type returns stringified array instead of array #19444

Open
opened 2026-04-15 18:32:19 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @sabaturgay on GitHub (Jan 17, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/7440

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Install better-auth@1.4.12.
  2. Configure additionalFields on the user with a string[] type:
    additionalFields: {
    	notificationTokens: {
    		type: 'string[]',
    		required: true,
    		input: true,
    	},
    }
    
  3. Create or update a user while providing an array value for notificationTokens:
    notificationTokens: ['token1', 'token2']
    

Current vs. Expected behavior

After upgrading from v1.4.4 → v1.4.12, additionalFields defined with type: 'string[]' no longer return an array.
Instead, the value is returned as a stringified JSON array (e.g. '["a","b"]'), even when a Zod validator is provided.

This behavior differs from previous versions and breaks existing code relying on array semantics.

Affected configuration

additionalFields: {
	notificationTokens: {
		type: 'string[]',
		required: true,
		// validator: {
		// 	input: z.array(z.string()).max(3),
		// },
		input: true,
	},
}

What version of Better Auth are you using?

1.4.12

System info

{
  "node": {
    "version": "v22.14.0",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.3.2"
  },
  "frameworks": [
    {
      "name": "react",
      "version": "19.1.0"
    },
    {
      "name": "hono",
      "version": "4.11.4"
    }
  ],
  "databases": [
    {
      "name": "drizzle",
      "version": "0.45.1"
    }
  ],
  "betterAuth": {
    "version": "1.4.4",
    "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
  },
});

Additional context

No response

Originally created by @sabaturgay on GitHub (Jan 17, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/7440 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Install `better-auth@1.4.12`. 2. Configure `additionalFields` on the user with a `string[]` type: ```ts additionalFields: { notificationTokens: { type: 'string[]', required: true, input: true, }, } ``` 3. Create or update a user while providing an array value for `notificationTokens`: ```ts notificationTokens: ['token1', 'token2'] ``` ### Current vs. Expected behavior After upgrading from **v1.4.4 → v1.4.12**, `additionalFields` defined with `type: 'string[]'` no longer return an array. Instead, the value is returned as a **stringified JSON array** (e.g. `'["a","b"]'`), even when a Zod validator is provided. This behavior differs from previous versions and breaks existing code relying on array semantics. ### Affected configuration ```ts additionalFields: { notificationTokens: { type: 'string[]', required: true, // validator: { // input: z.array(z.string()).max(3), // }, input: true, }, } ``` ### What version of Better Auth are you using? 1.4.12 ### System info ```bash { "node": { "version": "v22.14.0", "env": "development" }, "packageManager": { "name": "bun", "version": "1.3.2" }, "frameworks": [ { "name": "react", "version": "19.1.0" }, { "name": "hono", "version": "4.11.4" } ], "databases": [ { "name": "drizzle", "version": "0.45.1" } ], "betterAuth": { "version": "1.4.4", "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 }, }); ``` ### Additional context _No response_
GiteaMirror added the needs: infocorebug labels 2026-04-15 18:32:20 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 17, 2026):

It seems you're experiencing an issue where the additionalFields defined with type string[] is returning a stringified JSON array instead of an actual array when using better-auth@1.4.12. This behavior is indeed different from previous versions and can break existing code that relies on array semantics.

This appears to be a known issue. There has been some discussion in the community regarding similar scenarios where string[] fields were not correctly inferred, leading to inconsistent behavior in handling additional fields. Specifically, there was a bug reported about the string[] type fields that were wrongly cast, prompting the need for updates in the type inference logic [9].

Next Steps:

  1. Be sure to check for any patches or updates to the better-auth library that might address this issue in future releases.
  2. For the interim, you may want to consider implementing a workaround by manually parsing the stringified array until a fix is officially published.
  3. If you continue to experience issues or need more assistance, please tag @bekacru or @ping__, as they can provide you with specialized support.

What would you like to explore next regarding Better Auth or this specific issue?

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3764166701 --> @better-auth-agent[bot] commented on GitHub (Jan 17, 2026): It seems you're experiencing an issue where the `additionalFields` defined with type `string[]` is returning a stringified JSON array instead of an actual array when using `better-auth@1.4.12`. This behavior is indeed different from previous versions and can break existing code that relies on array semantics. This appears to be a known issue. There has been some discussion in the community regarding similar scenarios where `string[]` fields were not correctly inferred, leading to inconsistent behavior in handling additional fields. Specifically, there was a bug reported about the `string[]` type fields that were wrongly cast, prompting the need for updates in the type inference logic [[9]](https://github.com/better-auth/better-auth/pull/5795). ### Next Steps: 1. Be sure to check for any patches or updates to the `better-auth` library that might address this issue in future releases. 2. For the interim, you may want to consider implementing a workaround by manually parsing the stringified array until a fix is officially published. 3. If you continue to experience issues or need more assistance, please tag @bekacru or @ping__, as they can provide you with specialized support. What would you like to explore next regarding Better Auth or this specific issue? _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@dosubot[bot] commented on GitHub (Jan 17, 2026):

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

This is a known regression in better-auth 1.4.x: string[] fields in additionalFields are now stored as jsonb columns in Postgres instead of native text[] arrays. This causes them to be returned as stringified JSON arrays, breaking code that expects real arrays and causing issues with ORMs like Drizzle that expect native array types. This was not the case in 1.4.4, so your upgrade exposed this breaking change (details & workaround).

Workarounds:

  • Easiest: Change your Drizzle schema for the affected field(s) to use .jsonb() so it matches the actual column type.
  • To restore the old behavior (native arrays): Edit packages/better-auth/src/db/get-migration.ts, find the typeMap object in the getType function, and change the mapping for "string[]" under postgres from "jsonb" to "text[]". Then regenerate your migrations and migrate any existing data from jsonb to text[] if needed.

If you need step-by-step instructions for the manual fix or have a more complex setup, let me know!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3764170190 --> @dosubot[bot] commented on GitHub (Jan 17, 2026): <!-- Greeting --> Hi @sabaturgay! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known regression in better-auth 1.4.x: `string[]` fields in `additionalFields` are now stored as `jsonb` columns in Postgres instead of native `text[]` arrays. This causes them to be returned as stringified JSON arrays, breaking code that expects real arrays and causing issues with ORMs like Drizzle that expect native array types. This was not the case in 1.4.4, so your upgrade exposed this breaking change ([details & workaround](https://github.com/better-auth/better-auth/issues/6779)). **Workarounds:** - Easiest: Change your Drizzle schema for the affected field(s) to use `.jsonb()` so it matches the actual column type. - To restore the old behavior (native arrays): Edit `packages/better-auth/src/db/get-migration.ts`, find the `typeMap` object in the `getType` function, and change the mapping for `"string[]"` under `postgres` from `"jsonb"` to `"text[]"`. Then regenerate your migrations and migrate any existing data from `jsonb` to `text[]` if needed. If you need step-by-step instructions for the manual fix or have a more complex setup, let me know! <!-- 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/2e5b790e-4498-4849-95bb-aac31fec8d7b?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/2e5b790e-4498-4849-95bb-aac31fec8d7b?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/2e5b790e-4498-4849-95bb-aac31fec8d7b?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/2e5b790e-4498-4849-95bb-aac31fec8d7b?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/2e5b790e-4498-4849-95bb-aac31fec8d7b?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/2e5b790e-4498-4849-95bb-aac31fec8d7b?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/2e5b790e-4498-4849-95bb-aac31fec8d7b?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20known%20regression%20in%20better-auth%201.4.x%3A%20%60string%5B%5D%60%20fields%20in%20%60additionalFields%60%20are%20now%20stored%20as%20%60jsonb%60%20columns%20in%20Postgres%20instead%20of%20native%20%60text%5B%5D%60%20arrays.%20This%20causes%20them%20to%20be%20returned%20as%20stringified%20JSON%20arrays%2C%20breaking%20code%20that%20expects%20real%20arrays%20and%20causing%20issues%20with%20ORMs%20like%20Drizzle%20that%20expect%20native%20array%20types.%20This%20was%20not%20the%20case%20in%201.4.4%2C%20so%20your%20upgrade%20exposed%20this%20breaking%20change%C2%A0%28%5Bdetails%20%26%20workaround%5D%28https%3A//github.com/better-auth/better-auth/issues/6779%29%29.%0A%0A%2A%2AWorkarounds%3A%2A%2A%0A-%20Easiest%3A%20Change%20your%20Drizzle%20schema%20for%20the%20affected%20field%28s%29%20to%20use%20%60.jsonb%28%29%60%20so%20it%20matches%20the%20actual%20column%20type.%0A-%20To%20restore%20the%20old%20behavior%20%28native%20arrays%29%3A%20Edit%20%60packages/better-auth/src/db/get-migration.ts%60%2C%20find%20the%20%60typeMap%60%20object%20in%20the%20%60getType%60%20function%2C%20and%20change%20the%20mapping%20for%20%60%22string%5B%5D%22%60%20under%20%60postgres%60%20from%20%60%22jsonb%22%60%20to%20%60%22text%5B%5D%22%60.%20Then%20regenerate%20your%20migrations%20and%20migrate%20any%20existing%20data%20from%20%60jsonb%60%20to%20%60text%5B%5D%60%20if%20needed.%0A%0AIf%20you%20need%20step-by-step%20instructions%20for%20the%20manual%20fix%20or%20have%20a%20more%20complex%20setup%2C%20let%20me%20know%21)&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/7440)
Author
Owner

@ping-maxwell commented on GitHub (Jan 18, 2026):

What endpoint is returning the stringified array? Testing on my end after creating a user with a field name test set to ["hello", "world"] it does correctly return the values when I later call get-session:

Image
<!-- gh-comment-id:3765466825 --> @ping-maxwell commented on GitHub (Jan 18, 2026): What endpoint is returning the stringified array? Testing on my end after creating a user with a field name `test` set to `["hello", "world"]` it does correctly return the values when I later call `get-session`: <img width="444" height="52" alt="Image" src="https://github.com/user-attachments/assets/258e8ff3-1951-4b1e-8f4a-334944742936" />
Author
Owner

@sabaturgay commented on GitHub (Jan 18, 2026):

@ping-maxwell First I though the issue is on my side because I was calling drizzle directly instead of better-auth internal adapter and closed the issue. But just checked again and found the root cause.

The mode: 'json' column expects an array, but after better-auth@1.4.4 the value given to drizzle is string and drizzle stringify the string again and store it. Drizzle cannot catch the error because it does not check runtime values,. When querying the database directly via Drizzle, the value is returned as string (because 2 times stringify) but when using the better-auth internalAdapter, the value is correctly transformed back into an array which I think because of the extra transformer, which is why everything works as expected there.

So drizzle actually needs to return it as an array. I think the added transformer stringifies the value extra.

<!-- gh-comment-id:3765562868 --> @sabaturgay commented on GitHub (Jan 18, 2026): @ping-maxwell First I though the issue is on my side because I was calling drizzle directly instead of better-auth internal adapter and closed the issue. But just checked again and found the root cause. The `mode: 'json'` column expects an array, but after `better-auth@1.4.4` the value given to drizzle is string and drizzle stringify the string again and store it. Drizzle cannot catch the error because it does not check runtime values,. When querying the database **directly via Drizzle**, the value is returned as string (because 2 times stringify) but when using the **better-auth `internalAdapter`**, the value is correctly transformed back into an array which I think because of the extra transformer, which is why everything works as expected there. So drizzle actually needs to return it as an array. I think the added transformer stringifies the value extra.
Author
Owner

@ping-maxwell commented on GitHub (Jan 18, 2026):

Hey @sabaturgay is there anything else I could be of help for? I noticed you re-opened this issue

<!-- gh-comment-id:3765703158 --> @ping-maxwell commented on GitHub (Jan 18, 2026): Hey @sabaturgay is there anything else I could be of help for? I noticed you re-opened this issue
Author
Owner

@sabaturgay commented on GitHub (Jan 18, 2026):

@ping-maxwell First I though the issue is on my side because I was calling drizzle directly instead of better-auth internal adapter and closed the issue. But just checked again and found the root cause.

The mode: 'json' column expects an array, but after better-auth@1.4.4 the value given to drizzle is string and drizzle stringify the string again and store it. Drizzle cannot catch the error because it does not check runtime values,. When querying the database directly via Drizzle, the value is returned as string (because 2 times stringify) but when using the better-auth internalAdapter, the value is correctly transformed back into an array which I think because of the extra transformer, which is why everything works as expected there.

So drizzle actually needs to return it as an array. I think the added transformer stringifies the value extra.

I have already updated my previous comment, it will give additional context. Thanks in advance.

<!-- gh-comment-id:3765719170 --> @sabaturgay commented on GitHub (Jan 18, 2026): > @ping-maxwell First I though the issue is on my side because I was calling drizzle directly instead of better-auth internal adapter and closed the issue. But just checked again and found the root cause. > > The `mode: 'json'` column expects an array, but after `better-auth@1.4.4` the value given to drizzle is string and drizzle stringify the string again and store it. Drizzle cannot catch the error because it does not check runtime values,. When querying the database **directly via Drizzle**, the value is returned as string (because 2 times stringify) but when using the **better-auth `internalAdapter`**, the value is correctly transformed back into an array which I think because of the extra transformer, which is why everything works as expected there. > > So drizzle actually needs to return it as an array. I think the added transformer stringifies the value extra. > I have already updated my previous comment, it will give additional context. Thanks in advance.
Author
Owner

@sabaturgay commented on GitHub (Jan 22, 2026):

@ping-maxwell Just checked the changes between v1.4.4 and v1.4.6. I suspect the issue was introduced in the Drizzle adapter. I’m using the SQLite provider (D1 database).
Relevant diff:
https://github.com/better-auth/better-auth/compare/v1.4.4...v1.4.6
File:
packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts
This may be causing additional JSON stringification for string[] types, leading to the observed issue:

supportsJSON: config.provider === "pg" // even though mysql also supports it, mysql requires to pass stringified json anyway.
					? true
					: false,
supportsArrays: config.provider === "pg" ? true : false,
<!-- gh-comment-id:3786799391 --> @sabaturgay commented on GitHub (Jan 22, 2026): @ping-maxwell Just checked the changes between v1.4.4 and v1.4.6. I suspect the issue was introduced in the Drizzle adapter. I’m using the SQLite provider (D1 database). Relevant diff: https://github.com/better-auth/better-auth/compare/v1.4.4...v1.4.6 File: packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts This may be causing additional JSON stringification for string[] types, leading to [the observed issue:](https://github.com/better-auth/better-auth/issues/7440#issuecomment-3765562868) ```ts supportsJSON: config.provider === "pg" // even though mysql also supports it, mysql requires to pass stringified json anyway. ? true : false, supportsArrays: config.provider === "pg" ? true : false, ```
Author
Owner

@sabaturgay commented on GitHub (Jan 31, 2026):

Hey @ping-maxwell Just wanted to check if there's any update on this? It's currently a blocker for me to upgrade. Thanks!

<!-- gh-comment-id:3828125900 --> @sabaturgay commented on GitHub (Jan 31, 2026): Hey @ping-maxwell Just wanted to check if there's any update on this? It's currently a blocker for me to upgrade. Thanks!
Author
Owner

@Tomas2D commented on GitHub (Mar 12, 2026):

any update?

<!-- gh-comment-id:4047373954 --> @Tomas2D commented on GitHub (Mar 12, 2026): any update?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19444