[GH-ISSUE #6584] multiSession plugin can not infer types of username plugin and additional fields correctly after Next.js 16.0.7 upgrade #19193

Closed
opened 2026-04-15 18:00:39 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @dashidhy on GitHub (Dec 7, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6584

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

My auth.ts:

import 'dotenv/config';
import { betterAuth } from "better-auth";
import { username, multiSession, apiKey } from "better-auth/plugins";
import { nextCookies } from "better-auth/next-js";
import { neon } from "@neondatabase/serverless";
import { drizzle } from 'drizzle-orm/neon-http';
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { allSchema } from '@/db';


export const db = drizzle({ 
    client: neon(process.env.DATABASE_URL!), 
    schema: allSchema
});

export const auth = betterAuth({
    database: drizzleAdapter(db, { provider: "pg" }),
    emailAndPassword: {
        enabled: true,
        autoSignIn: false
    },
    plugins: [
        username({
            usernameNormalization: false,
            displayUsernameNormalization: false,
            usernameValidator: () => true
        }),
        multiSession({
            maximumSessions: 5
        }),
        apiKey({
            rateLimit: {
                enabled: true,
                timeWindow: 1000 * 60 * 1, // 1 min
                maxRequests: 100
            }
        }),
        nextCookies()
    ],
    user: {
        modelName: "lokiUser",
        additionalFields: {
            userTimezone: {
                type: "string",
                required: true
            },
            ttlockUsername: {
                type: "string",
                required: true
            },
            ttlockApiZone: {
                type: "string",
                required: true
            },
            ttlockAccessToken: {
                type: "string",
                required: false
            }
        }
    },
    advanced: {
        ipAddress: {
            ipAddressHeaders: ["x-forwarded-for", "x-real-ip", "x-client-ip"],
            disableIpTracking: false
        }
    }
});

My auth-client.ts

import { createAuthClient } from "better-auth/react";
import {
    usernameClient,
    multiSessionClient,
    apiKeyClient
} from "better-auth/client/plugins";
import { inferAdditionalFields } from "better-auth/client/plugins";
import type { auth } from "./auth";


export const authClient = createAuthClient({
    plugins: [ 
        usernameClient(),
        inferAdditionalFields<typeof auth>(),
        multiSessionClient(),
        apiKeyClient(),
    ] 
})

export const multiSession = authClient.multiSession;


export async function safeRevokeSession(sessionToken: string) {
    try {
        // Always attempt to revoke the session, even if it's not found in the list
        // This handles cases with duplicate or stale sessions
        await multiSession.revoke({ sessionToken });
    } catch (error) {
        // Silently ignore errors - session may already be revoked or invalid
        console.error('Failed to revoke session:', error);
    }
}

Current vs. Expected behavior

Problem

Image Image Image

The problem is that the types of new fields introduced by the username plugin and the additional fields are not inferred at all. This problem appeared just after I upgraded Next.js from 16.0.0 to 16.0.7 due to the security update, nothing else was changed.

Expected behavior

The field types should be inferred correctly.

What version of Better Auth are you using?

1.3.33, 1.4.5

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.1.0: Mon Oct 20 19:33:00 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T6020",
    "release": "25.1.0",
    "cpuCount": 12,
    "cpuModel": "Apple M2 Pro",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.14 GB"
  },
  "node": {
    "version": "v22.17.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.6.4"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "^16.0.7"
    },
    {
      "name": "react",
      "version": "^19.2.1"
    }
  ],
  "databases": [
    {
      "name": "drizzle",
      "version": "^0.44.7"
    },
    {
      "name": "kysely",
      "version": "^0.28.8"
    },
    {
      "name": "@neondatabase/serverless",
      "version": "^1.0.2"
    }
  ],
  "betterAuth": {
    "version": "^1.4.5",
    "config": null
  }
}

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

Types

Auth config (if applicable)

Shared in the "To reproduce" session.

Additional context

None

Originally created by @dashidhy on GitHub (Dec 7, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6584 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce ### My auth.ts: ```TypeScript import 'dotenv/config'; import { betterAuth } from "better-auth"; import { username, multiSession, apiKey } from "better-auth/plugins"; import { nextCookies } from "better-auth/next-js"; import { neon } from "@neondatabase/serverless"; import { drizzle } from 'drizzle-orm/neon-http'; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { allSchema } from '@/db'; export const db = drizzle({ client: neon(process.env.DATABASE_URL!), schema: allSchema }); export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg" }), emailAndPassword: { enabled: true, autoSignIn: false }, plugins: [ username({ usernameNormalization: false, displayUsernameNormalization: false, usernameValidator: () => true }), multiSession({ maximumSessions: 5 }), apiKey({ rateLimit: { enabled: true, timeWindow: 1000 * 60 * 1, // 1 min maxRequests: 100 } }), nextCookies() ], user: { modelName: "lokiUser", additionalFields: { userTimezone: { type: "string", required: true }, ttlockUsername: { type: "string", required: true }, ttlockApiZone: { type: "string", required: true }, ttlockAccessToken: { type: "string", required: false } } }, advanced: { ipAddress: { ipAddressHeaders: ["x-forwarded-for", "x-real-ip", "x-client-ip"], disableIpTracking: false } } }); ``` ### My auth-client.ts ```TypeScript import { createAuthClient } from "better-auth/react"; import { usernameClient, multiSessionClient, apiKeyClient } from "better-auth/client/plugins"; import { inferAdditionalFields } from "better-auth/client/plugins"; import type { auth } from "./auth"; export const authClient = createAuthClient({ plugins: [ usernameClient(), inferAdditionalFields<typeof auth>(), multiSessionClient(), apiKeyClient(), ] }) export const multiSession = authClient.multiSession; export async function safeRevokeSession(sessionToken: string) { try { // Always attempt to revoke the session, even if it's not found in the list // This handles cases with duplicate or stale sessions await multiSession.revoke({ sessionToken }); } catch (error) { // Silently ignore errors - session may already be revoked or invalid console.error('Failed to revoke session:', error); } } ``` ### Current vs. Expected behavior ### Problem <img width="504" height="102" alt="Image" src="https://github.com/user-attachments/assets/87d6e9d1-be96-4610-b943-a223fb1f6fba" /> <img width="612" height="73" alt="Image" src="https://github.com/user-attachments/assets/c108dfc8-5a76-4ba6-a137-5b76e721659b" /> <img width="1106" height="342" alt="Image" src="https://github.com/user-attachments/assets/79bc27ed-bb1c-451f-8398-004b0cd10aa7" /> The problem is that the types of new fields introduced by the username plugin and the additional fields are not inferred at all. This problem appeared just after I upgraded Next.js from 16.0.0 to 16.0.7 due to the security update, nothing else was changed. ### Expected behavior The field types should be inferred correctly. ### What version of Better Auth are you using? 1.3.33, 1.4.5 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.1.0: Mon Oct 20 19:33:00 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T6020", "release": "25.1.0", "cpuCount": 12, "cpuModel": "Apple M2 Pro", "totalMemory": "16.00 GB", "freeMemory": "0.14 GB" }, "node": { "version": "v22.17.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.6.4" }, "frameworks": [ { "name": "next", "version": "^16.0.7" }, { "name": "react", "version": "^19.2.1" } ], "databases": [ { "name": "drizzle", "version": "^0.44.7" }, { "name": "kysely", "version": "^0.28.8" }, { "name": "@neondatabase/serverless", "version": "^1.0.2" } ], "betterAuth": { "version": "^1.4.5", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Types ### Auth config (if applicable) ```typescript Shared in the "To reproduce" session. ``` ### Additional context None
GiteaMirror added the locked label 2026-04-15 18:00:39 -05:00
Author
Owner

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

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

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

DiagramDiscordGitHub

Diagram Join Star

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

@dosubot[bot] commented on GitHub (Dec 7, 2025):

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

This is a known issue with Better Auth's type inference pipeline, especially after recent updates to Next.js or TypeScript. The most common causes are:

  • The TypeScript flag "exactOptionalPropertyTypes": true in your tsconfig.json breaks type inference for plugin and additional fields. Set it to false to restore correct inference [1].
  • Force-casting plugins (e.g., as unknown as BetterAuthPlugin) suppresses type inference and should be avoided [2].
  • Type inference for additional fields on the client with inferAdditionalFields<typeof auth>() only works if the client can import the server's auth type. If your setup is decoupled, you must manually specify the fields on the client [3].
  • Sometimes, upgrading Next.js or changing module resolution (e.g., to "nodenext") can affect type propagation. Try setting "moduleResolution": "nodenext" in your tsconfig.json if you see inference issues after a Next.js upgrade [4].

If you have already checked the above and still see missing types, try these workarounds:

  • Redeclare your auth config as a const and use ReturnType<typeof betterAuth<typeof config>> for your Auth type, then use that type everywhere [5].
  • If type inference still fails, manually specify the additional fields in your client plugin config.
  • As a last resort, use a schema tool like drizzle-zod to generate types from your DB schema and use those types in your code [6].
  • Clear your build cache and restart your TypeScript server to rule out stale type artifacts [7].

Full static type inference for user fields in hooks and middleware is not yet 100% reliable in Better Auth 1.3.33 and 1.4.5, but these steps should restore most type safety for plugin and additional fields.

If none of these resolve the issue, try to isolate the problem in a minimal reproduction to help pinpoint whether the breakage is due to Next.js, Better Auth, or TypeScript changes.


References:

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:3622325818 --> @dosubot[bot] commented on GitHub (Dec 7, 2025): <!-- Greeting --> Hi @dashidhy! 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's type inference pipeline, especially after recent updates to Next.js or TypeScript. The most common causes are: - The TypeScript flag `"exactOptionalPropertyTypes": true` in your `tsconfig.json` breaks type inference for plugin and additional fields. Set it to `false` to restore correct inference [[1](https://github.com/better-auth/better-auth/issues/5159)]. - Force-casting plugins (e.g., `as unknown as BetterAuthPlugin`) suppresses type inference and should be avoided [[2](https://github.com/better-auth/better-auth/issues/5218)]. - Type inference for additional fields on the client with `inferAdditionalFields<typeof auth>()` only works if the client can import the server's `auth` type. If your setup is decoupled, you must manually specify the fields on the client [[3](https://github.com/better-auth/better-auth/discussions/3787)]. - Sometimes, upgrading Next.js or changing module resolution (e.g., to `"nodenext"`) can affect type propagation. Try setting `"moduleResolution": "nodenext"` in your `tsconfig.json` if you see inference issues after a Next.js upgrade [[4](https://github.com/better-auth/better-auth/issues/5538)]. If you have already checked the above and still see missing types, try these workarounds: - Redeclare your auth config as a `const` and use `ReturnType<typeof betterAuth<typeof config>>` for your `Auth` type, then use that type everywhere [[5](https://github.com/better-auth/better-auth/issues/5538)]. - If type inference still fails, manually specify the additional fields in your client plugin config. - As a last resort, use a schema tool like drizzle-zod to generate types from your DB schema and use those types in your code [[6](https://github.com/better-auth/better-auth/issues/5218)]. - Clear your build cache and restart your TypeScript server to rule out stale type artifacts [[7](https://github.com/better-auth/better-auth/issues/5625)]. Full static type inference for user fields in hooks and middleware is not yet 100% reliable in Better Auth 1.3.33 and 1.4.5, but these steps should restore most type safety for plugin and additional fields. If none of these resolve the issue, try to isolate the problem in a minimal reproduction to help pinpoint whether the breakage is due to Next.js, Better Auth, or TypeScript changes. --- **References:** - [exactOptionalPropertyTypes breaks plugin field inference](https://github.com/better-auth/better-auth/issues/5159) - [Type inference limitations and workarounds](https://github.com/better-auth/better-auth/issues/5218) - [Client/server type coupling and manual field specification](https://github.com/better-auth/better-auth/discussions/3787) - [moduleResolution and type inference](https://github.com/better-auth/better-auth/issues/5538) - [Redeclaring config and using ReturnType workaround](https://github.com/better-auth/better-auth/issues/5538) - [drizzle-zod workaround](https://github.com/better-auth/better-auth/issues/5218) - [Clearing cache and TypeScript server](https://github.com/better-auth/better-auth/issues/5625) <!-- 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/e5421c76-a9b3-4ebc-b831-4f5cdd48f3af?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/e5421c76-a9b3-4ebc-b831-4f5cdd48f3af?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/e5421c76-a9b3-4ebc-b831-4f5cdd48f3af?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/e5421c76-a9b3-4ebc-b831-4f5cdd48f3af?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/e5421c76-a9b3-4ebc-b831-4f5cdd48f3af?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/e5421c76-a9b3-4ebc-b831-4f5cdd48f3af?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/e5421c76-a9b3-4ebc-b831-4f5cdd48f3af?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%20issue%20with%20Better%20Auth%27s%20type%20inference%20pipeline%2C%20especially%20after%20recent%20updates%20to%20Next.js%20or%20TypeScript.%20The%20most%20common%20causes%20are%3A%0A%0A-%20The%20TypeScript%20flag%20%60%22exactOptionalPropertyTypes%22%3A%20true%60%20in%20your%20%60tsconfig.json%60%20breaks%20type%20inference%20for%20plugin%20and%20additional%20fields.%20Set%20it%20to%20%60false%60%20to%20restore%20correct%20inference%20%5B%5B1%5D%28https%3A//github.com/better-auth/better-auth/issues/5159%29%5D.%0A-%20Force-casting%20plugins%20%28e.g.%2C%20%60as%20unknown%20as%20BetterAuthPlugin%60%29%20suppresses%20type%20inference%20and%20should%20be%20avoided%20%5B%5B2%5D%28https%3A//github.com/better-auth/better-auth/issues/5218%29%5D.%0A-%20Type%20inference%20for%20additional%20fields%20on%20the%20client%20with%20%60inferAdditionalFields%3Ctypeof%20auth%3E%28%29%60%20only%20works%20if%20the%20client%20can%20import%20the%20server%27s%20%60auth%60%20type.%20If%20your%20setup%20is%20decoupled%2C%20you%20must%20manually%20specify%20the%20fields%20on%20the%20client%20%5B%5B3%5D%28https%3A//github.com/better-auth/better-auth/discussions/3787%29%5D.%0A-%20Sometimes%2C%20upgrading%20Next.js%20or%20changing%20module%20resolution%20%28e.g.%2C%20to%20%60%22nodenext%22%60%29%20can%20affect%20type%20propagation.%20Try%20setting%20%60%22moduleResolution%22%3A%20%22nodenext%22%60%20in%20your%20%60tsconfig.json%60%20if%20you%20see%20inference%20issues%20after%20a%20Next.js%20upgrade%20%5B%5B4%5D%28https%3A//github.com/better-auth/better-auth/issues/5538%29%5D.%0A%0AIf%20you%20have%20already%20checked%20the%20above%20and%20still%20see%20missing%20types%2C%20try%20these%20workarounds%3A%0A%0A-%20Redeclare%20your%20auth%20config%20as%20a%20%60const%60%20and%20use%20%60ReturnType%3Ctypeof%20betterAuth%3Ctypeof%20config%3E%3E%60%20for%20your%20%60Auth%60%20type%2C%20then%20use%20that%20type%20everywhere%20%5B%5B5%5D%28https%3A//github.com/better-auth/better-auth/issues/5538%29%5D.%0A-%20If%20type%20inference%20still%20fails%2C%20manually%20specify%20the%20additional%20fields%20in%20your%20client%20plugin%20config.%0A-%20As%20a%20last%20resort%2C%20use%20a%20schema%20tool%20like%20drizzle-zod%20to%20generate%20types%20from%20your%20DB%20schema%20and%20use%20those%20types%20in%20your%20code%20%5B%5B6%5D%28https%3A//github.com/better-auth/better-auth/issues/5218%29%5D.%0A-%20Clear%20your%20build%20cache%20and%20restart%20your%20TypeScript%20server%20to%20rule%20out%20stale%20type%20artifacts%20%5B%5B7%5D%28https%3A//github.com/better-auth/better-auth/issues/5625%29%5D.%0A%0AFull%20static%20type%20inference%20for%20user%20fields%20in%20hooks%20and%20middleware%20is%20not%20yet%20100%25%20reliable%20in%20Better%20Auth%201.3.33%20and%201.4.5%2C%20but%20these%20steps%20should%20restore%20most%20type%20safety%20for%20plugin%20and%20additional%20fields.%0A%0AIf%20none%20of%20these%20resolve%20the%20issue%2C%20try%20to%20isolate%20the%20problem%20in%20a%20minimal%20reproduction%20to%20help%20pinpoint%20whether%20the%20breakage%20is%20due%20to%20Next.js%2C%20Better%20Auth%2C%20or%20TypeScript%20changes.%0A%0A---%0A%0A%2A%2AReferences%3A%2A%2A%0A%0A-%20%5BexactOptionalPropertyTypes%20breaks%20plugin%20field%20inference%5D%28https%3A//github.com/better-auth/better-auth/issues/5159%29%0A-%20%5BType%20inference%20limitations%20and%20workarounds%5D%28https%3A//github.com/better-auth/better-auth/issues/5218%29%0A-%20%5BClient/server%20type%20coupling%20and%20manual%20field%20specification%5D%28https%3A//github.com/better-auth/better-auth/discussions/3787%29%0A-%20%5BmoduleResolution%20and%20type%20inference%5D%28https%3A//github.com/better-auth/better-auth/issues/5538%29%0A-%20%5BRedeclaring%20config%20and%20using%20ReturnType%20workaround%5D%28https%3A//github.com/better-auth/better-auth/issues/5538%29%0A-%20%5Bdrizzle-zod%20workaround%5D%28https%3A//github.com/better-auth/better-auth/issues/5218%29%0A-%20%5BClearing%20cache%20and%20TypeScript%20server%5D%28https%3A//github.com/better-auth/better-auth/issues/5625%29)&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/6584)
Author
Owner

@lauramosher commented on GitHub (Mar 3, 2026):

Can we reopen this as an issue since the original PR was reverted and a new one is not in the works anymore?

<!-- gh-comment-id:3993647036 --> @lauramosher commented on GitHub (Mar 3, 2026): Can we reopen this as an issue since the original PR was reverted and a new one is not in the works anymore?
Author
Owner

@github-actions[bot] commented on GitHub (Apr 1, 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:4166556083 --> @github-actions[bot] commented on GitHub (Apr 1, 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#19193