[GH-ISSUE #5900] TypeScript error when adding additionalFields to user with json type #19004

Closed
opened 2026-04-15 17:45:34 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @bennajah on GitHub (Nov 11, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5900

Originally assigned to: @ping-maxwell on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Add an additionalFields column to the user with type json and default values.
  2. Use auth.api.signUpEmail to create a new user and include the new additionalFields field in the request.
  3. Observe the TypeScript error that occurs.
Image

Current vs. Expected behavior

When adding a JSON field, TypeScript type infers the field as null | undefined instead of reflecting its actual structure or default value type.

What version of Better Auth are you using?

1.3.34

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Pro",
    "release": "10.0.26200",
    "cpuCount": 8,
    "cpuModel": "Intel(R) Xeon(R) CPU E5-1620 0 @ 3.60GHz",
    "totalMemory": "11.96 GB",
    "freeMemory": "4.00 GB"
  },
  "node": {
    "version": "v24.11.0",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.3.2"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "^16.0.1"
    },
    {
      "name": "react",
      "version": "^19.2.0"
    }
  ],
  "databases": [
    {
      "name": "drizzle",
      "version": "^0.44.7"
    },
    {
      "name": "@neondatabase/serverless",
      "version": "^1.0.2"
    }
  ],
  "betterAuth": {
    "version": "^1.3.34",
    "config": {
      "baseURL": "http://localhost:3000",
      "appName": "Acme",
      "emailAndPassword": {
        "enabled": true
      },
      "socialProviders": {
        "google": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        },
        "facebook": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        }
      },
      "account": {
        "accountLinking": {
          "enabled": true,
          "trustedProviders": [
            "google",
            "facebook"
          ]
        }
      },
      "user": {
        "additionalFields": {
          "preferences": {
            "type": "json",
            "required": false,
            "default": {
              "locale": "en",
              "theme": "system"
            }
          }
        }
      },
      "plugins": [
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        }
      ]
    }
  }
}

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

Types

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  ...
  user: {
    additionalFields: {
      preferences: {
        type: "json",
        required: false,
        default: {
          locale: "en",
          theme: "system",
        },
      },
    },
  },
});

Additional context

No response

Originally created by @bennajah on GitHub (Nov 11, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5900 Originally assigned to: @ping-maxwell on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Add an additionalFields column to the user with type json and default values. 2. Use auth.api.signUpEmail to create a new user and include the new additionalFields field in the request. 3. Observe the TypeScript error that occurs. <img width="1223" height="817" alt="Image" src="https://github.com/user-attachments/assets/85232fee-ad2c-4152-a2a7-97ed87562a82" /> ### Current vs. Expected behavior When adding a JSON field, TypeScript type infers the field as null | undefined instead of reflecting its actual structure or default value type. ### What version of Better Auth are you using? 1.3.34 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Pro", "release": "10.0.26200", "cpuCount": 8, "cpuModel": "Intel(R) Xeon(R) CPU E5-1620 0 @ 3.60GHz", "totalMemory": "11.96 GB", "freeMemory": "4.00 GB" }, "node": { "version": "v24.11.0", "env": "development" }, "packageManager": { "name": "bun", "version": "1.3.2" }, "frameworks": [ { "name": "next", "version": "^16.0.1" }, { "name": "react", "version": "^19.2.0" } ], "databases": [ { "name": "drizzle", "version": "^0.44.7" }, { "name": "@neondatabase/serverless", "version": "^1.0.2" } ], "betterAuth": { "version": "^1.3.34", "config": { "baseURL": "http://localhost:3000", "appName": "Acme", "emailAndPassword": { "enabled": true }, "socialProviders": { "google": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" }, "facebook": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" } }, "account": { "accountLinking": { "enabled": true, "trustedProviders": [ "google", "facebook" ] } }, "user": { "additionalFields": { "preferences": { "type": "json", "required": false, "default": { "locale": "en", "theme": "system" } } } }, "plugins": [ { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } } ] } } } ``` ### Which area(s) are affected? (Select all that apply) Types ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ ... user: { additionalFields: { preferences: { type: "json", required: false, default: { locale: "en", theme: "system", }, }, }, }, }); ``` ### Additional context _No response_
GiteaMirror added the lockedcorebug labels 2026-04-15 17:45:34 -05:00
Author
Owner

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

Tag @better-auth-agent if you would like an answer from the Agent

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3516605412 --> @better-auth-agent[bot] commented on GitHub (Nov 11, 2025): Tag @better-auth-agent if you would like an answer from the Agent <!-- 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 (Nov 11, 2025):

This is a known limitation in Better Auth's type inference for additionalFields of type "json". The library currently infers JSON fields as Record<string, any> (or sometimes null | undefined if optional), rather than using the structure of your default value. This happens because the type system does not automatically map your provided default object to a stricter TypeScript type for the field.

A recent fix improved inference for array types and updated JSON fields to always infer as Record<string, any>, but it does not infer the exact shape from your default value. So, even with a default like { locale: "en", theme: "system" }, TypeScript will not enforce or infer that structure for the preferences field—manual type augmentation or casting is still needed if you want stricter typing. You can see details of this fix here: PR #5778.

For now, if you want strong typing for your preferences field, you can cast it manually or define an interface and use it in your code.

To reply, just mention @dosu.


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

<!-- gh-comment-id:3516621767 --> @dosubot[bot] commented on GitHub (Nov 11, 2025): <!-- Answer --> This is a known limitation in Better Auth's type inference for additionalFields of type "json". The library currently infers JSON fields as Record<string, any> (or sometimes null | undefined if optional), rather than using the structure of your default value. This happens because the type system does not automatically map your provided default object to a stricter TypeScript type for the field. A recent fix improved inference for array types and updated JSON fields to always infer as Record<string, any>, but it does not infer the exact shape from your default value. So, even with a default like `{ locale: "en", theme: "system" }`, TypeScript will not enforce or infer that structure for the preferences field—manual type augmentation or casting is still needed if you want stricter typing. You can see details of this fix here: [PR #5778](https://github.com/better-auth/better-auth/pull/5778). For now, if you want strong typing for your preferences field, you can cast it manually or define an interface and use it in your code. <!-- 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/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?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/5900)
Author
Owner

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

This is a known limitation in Better Auth's type inference for additionalFields of type "json". The library currently infers JSON fields as Record<string, any> (or sometimes null | undefined if optional), rather than using the structure of your default value. This happens because the type system does not automatically map your provided default object to a stricter TypeScript type for the field.

A recent fix improved inference for array types and updated JSON fields to always infer as Record<string, any>, but it does not infer the exact shape from your default value. So, even with a default like { locale: "en", theme: "system" }, TypeScript will not enforce or infer that structure for the preferences field—manual type augmentation or casting is still needed if you want stricter typing. You can see details of this fix here: PR #5778.

For now, if you want strong typing for your preferences field, you can cast it manually or define an interface and use it in your code.

To reply, just mention @dosu.

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

Even when this field is marked as required, it’s still inferred as never instead of Record<string, any>.

Image
<!-- gh-comment-id:3516694584 --> @bennajah commented on GitHub (Nov 11, 2025): > This is a known limitation in Better Auth's type inference for additionalFields of type "json". The library currently infers JSON fields as Record<string, any> (or sometimes null | undefined if optional), rather than using the structure of your default value. This happens because the type system does not automatically map your provided default object to a stricter TypeScript type for the field. > > A recent fix improved inference for array types and updated JSON fields to always infer as Record<string, any>, but it does not infer the exact shape from your default value. So, even with a default like `{ locale: "en", theme: "system" }`, TypeScript will not enforce or infer that structure for the preferences field—manual type augmentation or casting is still needed if you want stricter typing. You can see details of this fix here: [PR #5778](https://github.com/better-auth/better-auth/pull/5778). > > For now, if you want strong typing for your preferences field, you can cast it manually or define an interface and use it in your code. > > _To reply, just mention [@dosu](https://go.dosu.dev/dosubot)._ > > How did I do? [Good](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/de4a9b9a-9224-4efa-8561-6bea25b5dd8e?feedback_type=other)  [![Chat with Dosu](https://camo.githubusercontent.com/d9ffebb979729c9ef0fc4e3090dbae5b17cabbfec8afe378ada6b81913d6ad8a/68747470733a2f2f646f73752e6465762f646f73752d636861742d62616467652e737667)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github) [![Join Discord](https://camo.githubusercontent.com/d562c2df5e4567ea41d37f1d91a4da0839d8341037045b103b2da268998de17f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6a6f696e2d3538363546323f6c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465266c6162656c3d)](https://go.dosu.dev/discord-bot) [![Share on X](https://camo.githubusercontent.com/4649f705e2396d6f328dbc8e800a0509c9c17b3b20253b36706c393df124b93d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f582d73686172652d626c61636b)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/5900) Even when this field is marked as required, it’s still inferred as never instead of Record<string, any>. <img width="1246" height="617" alt="Image" src="https://github.com/user-attachments/assets/cbc336b4-d96c-4d1a-ab30-0ee7456b5dbf" />
Author
Owner

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

i think it is not setup for handling json objects and arrays

<!-- gh-comment-id:3516959574 --> @rovertrack commented on GitHub (Nov 11, 2025): i think it is not setup for handling json objects and arrays
Author
Owner

@dosubot[bot] commented on GitHub (Feb 10, 2026):

Hi, @bennajah. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You reported a TypeScript typing issue where JSON-typed additionalFields are inferred as null or undefined instead of their actual structure.
  • I confirmed this is a known limitation; Better Auth infers JSON fields as Record<string, any> or null/undefined but does not infer exact shapes from default values.
  • You noted that required JSON fields are still inferred as never, and another user mentioned incomplete support for JSON objects and arrays.
  • Currently, manual type casting or interface definitions are needed to achieve stricter typing.
  • The issue remains unresolved with no recent updates or fixes.

Next Steps:

  • Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thank you for your understanding and contribution!

<!-- gh-comment-id:3878974551 --> @dosubot[bot] commented on GitHub (Feb 10, 2026): Hi, @bennajah. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary:** - You reported a TypeScript typing issue where JSON-typed additionalFields are inferred as null or undefined instead of their actual structure. - I confirmed this is a known limitation; Better Auth infers JSON fields as Record<string, any> or null/undefined but does not infer exact shapes from default values. - You noted that required JSON fields are still inferred as never, and another user mentioned incomplete support for JSON objects and arrays. - Currently, manual type casting or interface definitions are needed to achieve stricter typing. - The issue remains unresolved with no recent updates or fixes. **Next Steps:** - Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open. - Otherwise, this issue will be automatically closed in 7 days. Thank you for your understanding and contribution!
Author
Owner

@bennajah commented on GitHub (Feb 10, 2026):

Hi, @bennajah. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You reported a TypeScript typing issue where JSON-typed additionalFields are inferred as null or undefined instead of their actual structure.
  • I confirmed this is a known limitation; Better Auth infers JSON fields as Record<string, any> or null/undefined but does not infer exact shapes from default values.
  • You noted that required JSON fields are still inferred as never, and another user mentioned incomplete support for JSON objects and arrays.
  • Currently, manual type casting or interface definitions are needed to achieve stricter typing.
  • The issue remains unresolved with no recent updates or fixes.

Next Steps:

  • Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thank you for your understanding and contribution!

now type is Record<string, any> | null | undefined

<!-- gh-comment-id:3879608749 --> @bennajah commented on GitHub (Feb 10, 2026): > Hi, [@bennajah](https://github.com/bennajah). I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. > > **Issue Summary:** > > * You reported a TypeScript typing issue where JSON-typed additionalFields are inferred as null or undefined instead of their actual structure. > * I confirmed this is a known limitation; Better Auth infers JSON fields as Record<string, any> or null/undefined but does not infer exact shapes from default values. > * You noted that required JSON fields are still inferred as never, and another user mentioned incomplete support for JSON objects and arrays. > * Currently, manual type casting or interface definitions are needed to achieve stricter typing. > * The issue remains unresolved with no recent updates or fixes. > > **Next Steps:** > > * Please let me know if this issue is still relevant with the latest version of better-auth by commenting here to keep the discussion open. > * Otherwise, this issue will be automatically closed in 7 days. > > Thank you for your understanding and contribution! now type is `Record<string, any> | null | undefined`
Author
Owner

@Sparticuz commented on GitHub (Feb 13, 2026):

It would be helpful to be able to just pass the type. I'm storing an object of Record<string, string[]> (technically Record<string, PermissionLevels[]>, but it's a string[] with const)

<!-- gh-comment-id:3898237437 --> @Sparticuz commented on GitHub (Feb 13, 2026): It would be helpful to be able to just pass the type. I'm storing an object of `Record<string, string[]>` (technically `Record<string, PermissionLevels[]>`, but it's a `string[]` with `const`)
Author
Owner

@ping-maxwell commented on GitHub (Mar 27, 2026):

Just checked on latest and the issue is resolved.

<!-- gh-comment-id:4143673669 --> @ping-maxwell commented on GitHub (Mar 27, 2026): Just checked on latest and the issue is resolved.
Author
Owner

@github-actions[bot] commented on GitHub (Apr 4, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4185770820 --> @github-actions[bot] commented on GitHub (Apr 4, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19004