[GH-ISSUE #5637] Typescript error in auth export #18940

Closed
opened 2026-04-15 17:40:23 -05:00 by GiteaMirror · 8 comments
Owner

Originally created by @satish-buildin2 on GitHub (Oct 28, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5637

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

after updating to the latest version of better auth ie "better-auth": "^1.3.33", i am facing type error in the auth export which was not before.
export const auth = betterAuth({
...
i also type caste into
export const auth: Auth = betterAuth({
...
alos tried type infer of betterAuth but didn't work.

Current vs. Expected behavior

current:
auth word shows red type error
expected:
no type error

What version of Better Auth are you using?

^1.3.33

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#33~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 19 17:02:30 UTC 2",
    "release": "6.14.0-33-generic",
    "cpuCount": 16,
    "cpuModel": "12th Gen Intel(R) Core(TM) i5-1240P",
    "totalMemory": "15.25 GB",
    "freeMemory": "4.68 GB"
  },
  "node": {
    "version": "v22.17.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.5.2"
  },
  "frameworks": [
    {
      "name": "express",
      "version": "^5.1.0"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "^1.3.33",
    "config": {
      "secret": "[REDACTED]",
      "baseURL": "http://localhost:3000",
      "trustedOrigins": [
        "http://localhost:5173"
      ],
      "errorURL": "http://localhost:5173",
      "user": {
        "additionalFields": {
          "isOnboardingComplete": {
            "type": "boolean",
            "defaultValue": false,
            "required": false
          },
          "timezone": {
            "type": "string",
            "defaultValue": "Europe/London",
            "required": false
          }
        }
      },
      "account": {
        "accountLinking": {
          "enabled": true,
          "allowDifferentEmails": false,
          "updateUserInfoOnLink": true
        }
      },
      "plugins": [
        {
          "name": "admin",
          "config": {
            "id": "admin",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "USER_ALREADY_EXISTS": "User already exists.",
              "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.",
              "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself",
              "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users",
              "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users",
              "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users",
              "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]",
              "BANNED_USER": "You have been banned from this application",
              "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user",
              "NO_DATA_TO_UPDATE": "No data to update",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users",
              "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself",
              "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value"
            },
            "schema": {
              "user": {
                "fields": {
                  "role": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banned": {
                    "type": "boolean",
                    "defaultValue": false,
                    "required": false,
                    "input": false
                  },
                  "banReason": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banExpires": {
                    "type": "date",
                    "required": false,
                    "input": false
                  }
                }
              },
              "session": {
                "fields": {
                  "impersonatedBy": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "options": {
              "defaultRole": "user",
              "adminRoles": [
                "admin"
              ]
            }
          }
        },
        {
          "name": "stripe",
          "config": {
            "id": "stripe",
            "endpoints": {},
            "schema": {
              "subscription": {
                "fields": {
                  "plan": {
                    "type": "string",
                    "required": true
                  },
                  "referenceId": {
                    "type": "string",
                    "required": true
                  },
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  },
                  "stripeSubscriptionId": {
                    "type": "string",
                    "required": false
                  },
                  "status": {
                    "type": "string",
                    "defaultValue": "incomplete"
                  },
                  "periodStart": {
                    "type": "date",
                    "required": false
                  },
                  "periodEnd": {
                    "type": "date",
                    "required": false
                  },
                  "trialStart": {
                    "type": "date",
                    "required": false
                  },
                  "trialEnd": {
                    "type": "date",
                    "required": false
                  },
                  "cancelAtPeriodEnd": {
                    "type": "boolean",
                    "required": false,
                    "defaultValue": false
                  },
                  "seats": {
                    "type": "number",
                    "required": false
                  }
                }
              },
              "user": {
                "fields": {
                  "stripeCustomerId": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            }
          }
        }
      ],
      "emailAndPassword": {
        "enabled": true,
        "requireEmailVerification": true
      },
      "emailVerification": {
        "sendOnSignUp": true,
        "autoSignInAfterVerification": true
      },
      "session": {
        "expiresIn": 604800,
        "updateAge": 86400
      },
      "advanced": {
        "defaultCookieAttributes": {
          "sameSite": "lax",
          "secure": false,
          "httpOnly": true
        }
      },
      "socialProviders": {
        "google": {
          "prompt": "select_account consent",
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]",
          "scope": [
            "openid",
            "email",
            "profile",
            "https://www.googleapis.com/auth/gmail.send"
          ],
          "accessType": "offline"
        }
      },
      "databaseHooks": {
        "account": {
          "create": {}
        }
      },
      "hooks": {}
    }
  }
}

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

Types

Auth config (if applicable)

import {
  BETTER_AUTH_SECRET,
  BETTER_AUTH_URL,
  CORS_ORIGIN,
  GOOGLE_CLIENT_ID,
  GOOGLE_CLIENT_SECRET,
  IS_PROD,
  REQUIRE_EMAIL_VERIFICATION,
  STRIPE_SECRET_KEY,
  STRIPE_WEBHOOK_SECRET,
} from "@/config/constants";
import {
  addProviderEmail,
  ProviderId,
} from "@/features/user/services/addProviderEmail.service";
import { MailClient } from "@/lib/mail-client";
import { client } from "@/lib/mongo";
import { stripe } from "@better-auth/stripe";
import { userRoleEnum } from "@packages/shared/schemas/user";
import { logger } from "@packages/shared/utils";
import { betterAuth } from "better-auth";
import { mongodbAdapter } from "better-auth/adapters/mongodb";
import { admin, createAuthMiddleware } from "better-auth/plugins";
import Stripe from "stripe";
import { STRIPE_PLANS } from "./stripe";

// Using MailClient object-based approach
const stripeClient = new Stripe(STRIPE_SECRET_KEY, {
  apiVersion: "2025-09-30.clover", // Latest API version as of Stripe SDK v19
});
export const auth = betterAuth({
  database: mongodbAdapter(client),
  secret: BETTER_AUTH_SECRET,
  baseURL: BETTER_AUTH_URL,
  trustedOrigins: [CORS_ORIGIN],
  errorURL: CORS_ORIGIN,
  user: {
    additionalFields: {
      isOnboardingComplete: {
        type: "boolean",
        defaultValue: false,
        required: false,
      },
      timezone: {
        type: "string",
        defaultValue: "Europe/London",
        required: false,
      },
    },
  },
  account: {
    accountLinking: {
      enabled: true,
      allowDifferentEmails: false,
      updateUserInfoOnLink: true,
    },
  },
  plugins: [
    admin({
      defaultRole: userRoleEnum.USER,
      adminRoles: [userRoleEnum.ADMIN],
    }),
    stripe({
      stripeClient,
      stripeWebhookSecret: STRIPE_WEBHOOK_SECRET,
      createCustomerOnSignUp: true,
      subscription: {
        enabled: true,
        plans: STRIPE_PLANS,
      },
    }),
  ],
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: REQUIRE_EMAIL_VERIFICATION,
    sendResetPassword: async ({ user, url, token }, request) => {
      await MailClient.sendPasswordResetEmail(user.email, user.name, url);
    },
  },
  emailVerification: {
    sendOnSignUp: true,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async ({ user, url, token }, request) => {
      await MailClient.sendVerificationEmail(user.email, user.name, url);
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24, // 1 day
  },
  advanced: {
    defaultCookieAttributes: {
      sameSite: "lax",
      secure: IS_PROD,
      httpOnly: true,
    },
  },
  socialProviders: {
    google: {
      prompt: "select_account consent",
      clientId: GOOGLE_CLIENT_ID,
      clientSecret: GOOGLE_CLIENT_SECRET,
      scope: [
        "openid",
        "email",
        "profile",
        "https://www.googleapis.com/auth/gmail.send",
      ],
      accessType: "offline", // Required to get refresh tokens
    },
    // microsoft: {
    //   clientId: MICROSOFT_CLIENT_ID,
    //   clientSecret: MICROSOFT_CLIENT_SECRET,
    //   tenantId: "common",
    //   prompt: "select_account",
    // },
  },
  databaseHooks: {
    account: {
      create: {
        after: async (account) => {
          // skip if providerId is credentials
          if (account.providerId === "credentials") {
            return;
          }

          // Use service to add provider email
          await addProviderEmail(
            account.id,
            account.providerId as ProviderId,
            account.accessToken || undefined
          );
        },
      },
    },
  },
  hooks: {
    before: createAuthMiddleware(async (ctx) => {
      if (ctx.path === "/error") {
        const { error } = ctx.query as { error?: string };
        logger.error(new Error("Auth error"), "AUTH");

        let redirectUrl = `${CORS_ORIGIN}/?error=${encodeURIComponent(
          "Authentication Error"
        )}&error_description=${encodeURIComponent("Failed to authenticate")}`;

        if (error === "banned") {
          redirectUrl = `${CORS_ORIGIN}/?error=${encodeURIComponent(
            "You have been banned"
          )}&error_description=${encodeURIComponent("Contact support team")}`;
        }

        throw ctx.redirect(redirectUrl);
      }
    }),
  },
});

// Use the shared types for consistency
export type Session = typeof auth.$Infer.Session.session;
export type User = typeof auth.$Infer.Session.user;

Additional context

The inferred type of 'auth' cannot be named without a reference to '.pnpm/@better-auth+core@1.3.33_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.18_better-cal_7d993e08fee368dcdde874190a187847/node_modules/@better-auth/core/db/adapter'. This is likely not portable. A type annotation is necessary.ts(2742)

now:
type User = {
id: string;
createdAt: Date;
updatedAt: Date;
email: string;
emailVerified: boolean;
name: string;
image?: string | null | undefined;
isOnboardingComplete: boolean | null | undefined;
timezone: string | null | undefined;
banned: boolean | null | undefined;
role?: string | null | undefined;
banReason?: string | null | undefined;
banExpires?: Date | null | undefined;
}

when used:
export const auth :Auth = ...
type User = {
id: string;
createdAt: Date;
updatedAt: Date;
email: string;
emailVerified: boolean;
name: string;
image?: string | null | undefined;
}

Originally created by @satish-buildin2 on GitHub (Oct 28, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5637 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce after updating to the latest version of better auth ie "better-auth": "^1.3.33", i am facing type error in the auth export which was not before. export const auth = betterAuth({ ... i also type caste into export const auth: Auth = betterAuth({ ... alos tried type infer of betterAuth but didn't work. ### Current vs. Expected behavior current: auth word shows red type error expected: no type error ### What version of Better Auth are you using? ^1.3.33 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#33~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 19 17:02:30 UTC 2", "release": "6.14.0-33-generic", "cpuCount": 16, "cpuModel": "12th Gen Intel(R) Core(TM) i5-1240P", "totalMemory": "15.25 GB", "freeMemory": "4.68 GB" }, "node": { "version": "v22.17.1", "env": "development" }, "packageManager": { "name": "npm", "version": "11.5.2" }, "frameworks": [ { "name": "express", "version": "^5.1.0" } ], "databases": null, "betterAuth": { "version": "^1.3.33", "config": { "secret": "[REDACTED]", "baseURL": "http://localhost:3000", "trustedOrigins": [ "http://localhost:5173" ], "errorURL": "http://localhost:5173", "user": { "additionalFields": { "isOnboardingComplete": { "type": "boolean", "defaultValue": false, "required": false }, "timezone": { "type": "string", "defaultValue": "Europe/London", "required": false } } }, "account": { "accountLinking": { "enabled": true, "allowDifferentEmails": false, "updateUserInfoOnLink": true } }, "plugins": [ { "name": "admin", "config": { "id": "admin", "hooks": { "after": [ {} ] }, "endpoints": {}, "$ERROR_CODES": { "FAILED_TO_CREATE_USER": "Failed to create user", "USER_ALREADY_EXISTS": "User already exists.", "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.", "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself", "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role", "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions", "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users", "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users", "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions", "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users", "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]", "BANNED_USER": "You have been banned from this application", "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user", "NO_DATA_TO_UPDATE": "No data to update", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users", "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself", "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value" }, "schema": { "user": { "fields": { "role": { "type": "string", "required": false, "input": false }, "banned": { "type": "boolean", "defaultValue": false, "required": false, "input": false }, "banReason": { "type": "string", "required": false, "input": false }, "banExpires": { "type": "date", "required": false, "input": false } } }, "session": { "fields": { "impersonatedBy": { "type": "string", "required": false } } } }, "options": { "defaultRole": "user", "adminRoles": [ "admin" ] } } }, { "name": "stripe", "config": { "id": "stripe", "endpoints": {}, "schema": { "subscription": { "fields": { "plan": { "type": "string", "required": true }, "referenceId": { "type": "string", "required": true }, "stripeCustomerId": { "type": "string", "required": false }, "stripeSubscriptionId": { "type": "string", "required": false }, "status": { "type": "string", "defaultValue": "incomplete" }, "periodStart": { "type": "date", "required": false }, "periodEnd": { "type": "date", "required": false }, "trialStart": { "type": "date", "required": false }, "trialEnd": { "type": "date", "required": false }, "cancelAtPeriodEnd": { "type": "boolean", "required": false, "defaultValue": false }, "seats": { "type": "number", "required": false } } }, "user": { "fields": { "stripeCustomerId": { "type": "string", "required": false } } } } } } ], "emailAndPassword": { "enabled": true, "requireEmailVerification": true }, "emailVerification": { "sendOnSignUp": true, "autoSignInAfterVerification": true }, "session": { "expiresIn": 604800, "updateAge": 86400 }, "advanced": { "defaultCookieAttributes": { "sameSite": "lax", "secure": false, "httpOnly": true } }, "socialProviders": { "google": { "prompt": "select_account consent", "clientId": "[REDACTED]", "clientSecret": "[REDACTED]", "scope": [ "openid", "email", "profile", "https://www.googleapis.com/auth/gmail.send" ], "accessType": "offline" } }, "databaseHooks": { "account": { "create": {} } }, "hooks": {} } } } ``` ### Which area(s) are affected? (Select all that apply) Types ### Auth config (if applicable) ```typescript import { BETTER_AUTH_SECRET, BETTER_AUTH_URL, CORS_ORIGIN, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, IS_PROD, REQUIRE_EMAIL_VERIFICATION, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, } from "@/config/constants"; import { addProviderEmail, ProviderId, } from "@/features/user/services/addProviderEmail.service"; import { MailClient } from "@/lib/mail-client"; import { client } from "@/lib/mongo"; import { stripe } from "@better-auth/stripe"; import { userRoleEnum } from "@packages/shared/schemas/user"; import { logger } from "@packages/shared/utils"; import { betterAuth } from "better-auth"; import { mongodbAdapter } from "better-auth/adapters/mongodb"; import { admin, createAuthMiddleware } from "better-auth/plugins"; import Stripe from "stripe"; import { STRIPE_PLANS } from "./stripe"; // Using MailClient object-based approach const stripeClient = new Stripe(STRIPE_SECRET_KEY, { apiVersion: "2025-09-30.clover", // Latest API version as of Stripe SDK v19 }); export const auth = betterAuth({ database: mongodbAdapter(client), secret: BETTER_AUTH_SECRET, baseURL: BETTER_AUTH_URL, trustedOrigins: [CORS_ORIGIN], errorURL: CORS_ORIGIN, user: { additionalFields: { isOnboardingComplete: { type: "boolean", defaultValue: false, required: false, }, timezone: { type: "string", defaultValue: "Europe/London", required: false, }, }, }, account: { accountLinking: { enabled: true, allowDifferentEmails: false, updateUserInfoOnLink: true, }, }, plugins: [ admin({ defaultRole: userRoleEnum.USER, adminRoles: [userRoleEnum.ADMIN], }), stripe({ stripeClient, stripeWebhookSecret: STRIPE_WEBHOOK_SECRET, createCustomerOnSignUp: true, subscription: { enabled: true, plans: STRIPE_PLANS, }, }), ], emailAndPassword: { enabled: true, requireEmailVerification: REQUIRE_EMAIL_VERIFICATION, sendResetPassword: async ({ user, url, token }, request) => { await MailClient.sendPasswordResetEmail(user.email, user.name, url); }, }, emailVerification: { sendOnSignUp: true, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url, token }, request) => { await MailClient.sendVerificationEmail(user.email, user.name, url); }, }, session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24, // 1 day }, advanced: { defaultCookieAttributes: { sameSite: "lax", secure: IS_PROD, httpOnly: true, }, }, socialProviders: { google: { prompt: "select_account consent", clientId: GOOGLE_CLIENT_ID, clientSecret: GOOGLE_CLIENT_SECRET, scope: [ "openid", "email", "profile", "https://www.googleapis.com/auth/gmail.send", ], accessType: "offline", // Required to get refresh tokens }, // microsoft: { // clientId: MICROSOFT_CLIENT_ID, // clientSecret: MICROSOFT_CLIENT_SECRET, // tenantId: "common", // prompt: "select_account", // }, }, databaseHooks: { account: { create: { after: async (account) => { // skip if providerId is credentials if (account.providerId === "credentials") { return; } // Use service to add provider email await addProviderEmail( account.id, account.providerId as ProviderId, account.accessToken || undefined ); }, }, }, }, hooks: { before: createAuthMiddleware(async (ctx) => { if (ctx.path === "/error") { const { error } = ctx.query as { error?: string }; logger.error(new Error("Auth error"), "AUTH"); let redirectUrl = `${CORS_ORIGIN}/?error=${encodeURIComponent( "Authentication Error" )}&error_description=${encodeURIComponent("Failed to authenticate")}`; if (error === "banned") { redirectUrl = `${CORS_ORIGIN}/?error=${encodeURIComponent( "You have been banned" )}&error_description=${encodeURIComponent("Contact support team")}`; } throw ctx.redirect(redirectUrl); } }), }, }); // Use the shared types for consistency export type Session = typeof auth.$Infer.Session.session; export type User = typeof auth.$Infer.Session.user; ``` ### Additional context The inferred type of 'auth' cannot be named without a reference to '.pnpm/@better-auth+core@1.3.33_@better-auth+utils@0.3.0_@better-fetch+fetch@1.1.18_better-cal_7d993e08fee368dcdde874190a187847/node_modules/@better-auth/core/db/adapter'. This is likely not portable. A type annotation is necessary.ts(2742) now: type User = { id: string; createdAt: Date; updatedAt: Date; email: string; emailVerified: boolean; name: string; image?: string | null | undefined; isOnboardingComplete: boolean | null | undefined; timezone: string | null | undefined; banned: boolean | null | undefined; role?: string | null | undefined; banReason?: string | null | undefined; banExpires?: Date | null | undefined; } when used: export const auth :Auth = ... type User = { id: string; createdAt: Date; updatedAt: Date; email: string; emailVerified: boolean; name: string; image?: string | null | undefined; }
GiteaMirror added the locked label 2026-04-15 17:40:23 -05:00
Author
Owner

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

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

This TypeScript error happens because the inferred type of auth references internal types from Better Auth (like @better-auth/core/db/adapter) that aren't exported at the top level, making the type non-portable—especially in monorepos or with pnpm setups. This is a known issue in Better Auth v1.3.33 and is triggered by using additionalFields or plugins in your config. Type casting or inferring with betterAuth doesn't resolve it because the underlying types still leak references to internal modules that TypeScript can't serialize for export details.

Workarounds:

  • The most reliable fix is to use an explicit type annotation when exporting auth, like:
    export const auth = betterAuth(authConfig) as ReturnType<typeof betterAuth<typeof authConfig>>;
    
    This makes the type portable and avoids the error, but you may lose some plugin-specific typings example.
  • If you need full type inference for plugins, you can try disabling "declaration" and "declarationMap" in your tsconfig.json (if your build system allows), which prevents TypeScript from emitting problematic declaration files example.
  • If you see this error in a monorepo, it's often due to multiple copies of dependencies or strict TypeScript settings like "exactOptionalPropertyTypes": true. Setting this to false can help, but reduces type safety details.

Recent changes in Better Auth plugins and adapters (like the admin and organization plugins) added more explicit type exports, but the core issue with deep internal type references remains until a major refactor in future versions see PRs.

For now, explicit type annotation or disabling declaration generation are the best options. If you need to infer custom user/session types, use typeof auth.$Infer.Session.user for consistency with your additional fields and plugins.

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:3455325570 --> @dosubot[bot] commented on GitHub (Oct 28, 2025): <!-- Greeting --> Hi @satish-buildin2! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This TypeScript error happens because the inferred type of `auth` references internal types from Better Auth (like `@better-auth/core/db/adapter`) that aren't exported at the top level, making the type non-portable—especially in monorepos or with pnpm setups. This is a known issue in Better Auth v1.3.33 and is triggered by using additionalFields or plugins in your config. Type casting or inferring with `betterAuth` doesn't resolve it because the underlying types still leak references to internal modules that TypeScript can't serialize for export [details](https://github.com/better-auth/better-auth/issues/4250). **Workarounds:** - The most reliable fix is to use an explicit type annotation when exporting `auth`, like: ```ts export const auth = betterAuth(authConfig) as ReturnType<typeof betterAuth<typeof authConfig>>; ``` This makes the type portable and avoids the error, but you may lose some plugin-specific typings [example](https://github.com/better-auth/better-auth/issues/4250). - If you need full type inference for plugins, you can try disabling `"declaration"` and `"declarationMap"` in your `tsconfig.json` (if your build system allows), which prevents TypeScript from emitting problematic declaration files [example](https://github.com/better-auth/better-auth/issues/5122). - If you see this error in a monorepo, it's often due to multiple copies of dependencies or strict TypeScript settings like `"exactOptionalPropertyTypes": true`. Setting this to `false` can help, but reduces type safety [details](https://github.com/better-auth/better-auth/issues/5574). Recent changes in Better Auth plugins and adapters (like the admin and organization plugins) added more explicit type exports, but the core issue with deep internal type references remains until a major refactor in future versions [see PRs](https://github.com/better-auth/better-auth/pull/3628). For now, explicit type annotation or disabling declaration generation are the best options. If you need to infer custom user/session types, use `typeof auth.$Infer.Session.user` for consistency with your additional fields and plugins. <!-- 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/0c729bea-36c7-4530-972d-b5713bce16b2?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/0c729bea-36c7-4530-972d-b5713bce16b2?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/0c729bea-36c7-4530-972d-b5713bce16b2?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/0c729bea-36c7-4530-972d-b5713bce16b2?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/0c729bea-36c7-4530-972d-b5713bce16b2?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/0c729bea-36c7-4530-972d-b5713bce16b2?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/0c729bea-36c7-4530-972d-b5713bce16b2?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/5637)
Author
Owner

@ghassenbenghorbal commented on GitHub (Oct 28, 2025):

This is a known issue that occurs when you use additionalFields. I opened an issue 3 weeks ago and still waiting for feedback. #5122

<!-- gh-comment-id:3456401911 --> @ghassenbenghorbal commented on GitHub (Oct 28, 2025): This is a known issue that occurs when you use additionalFields. I opened an issue 3 weeks ago and still waiting for feedback. #5122
Author
Owner

@Bekacru commented on GitHub (Oct 28, 2025):

@ghassenbenghorbal can you try 1.4-beta versions and confirm with me if it's still an issue?

<!-- gh-comment-id:3458739466 --> @Bekacru commented on GitHub (Oct 28, 2025): @ghassenbenghorbal can you try 1.4-beta versions and confirm with me if it's still an issue?
Author
Owner

@himself65 commented on GitHub (Nov 14, 2025):

I think we have this fixed in 1.4

<!-- gh-comment-id:3531185842 --> @himself65 commented on GitHub (Nov 14, 2025): I think we have this fixed in 1.4
Author
Owner

@jonthomp commented on GitHub (Nov 15, 2025):

@himself65 I've just tried it, the problem still exists in 1.4.0-beta.20.

It appears to be related to using Zod 3.

<!-- gh-comment-id:3536701962 --> @jonthomp commented on GitHub (Nov 15, 2025): @himself65 I've just tried it, the problem still exists in 1.4.0-beta.20. It appears to be related to using Zod 3.
Author
Owner

@himself65 commented on GitHub (Nov 15, 2025):

Thanks for the feedback, i will take a look

<!-- gh-comment-id:3536724339 --> @himself65 commented on GitHub (Nov 15, 2025): Thanks for the feedback, i will take a look
Author
Owner

@jonthomp commented on GitHub (Nov 15, 2025):

Overriding better-auth to use Zod 4 has resolved it for me for now.

<!-- gh-comment-id:3536726146 --> @jonthomp commented on GitHub (Nov 15, 2025): Overriding better-auth to use Zod 4 has resolved it for me for now.
Author
Owner

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

Hi, @satish-buildin2. 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 TypeScript errors in the auth export after updating to better-auth v1.3.33, related to internal type references leaking from plugins or additionalFields usage.
  • The issue stems from non-exported internal types causing type portability problems.
  • Workarounds suggested include explicit type annotations or disabling declaration generation.
  • Other users confirmed the problem persists in v1.4 beta, especially with Zod 3, but switching to Zod 4 temporarily resolves it.
  • Maintainers are aware and investigating fixes for future releases.

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, I will automatically close this issue in 7 days.

Thank you for your understanding and contribution!

<!-- gh-comment-id:3902115283 --> @dosubot[bot] commented on GitHub (Feb 14, 2026): Hi, @satish-buildin2. 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 TypeScript errors in the auth export after updating to better-auth v1.3.33, related to internal type references leaking from plugins or additionalFields usage. - The issue stems from non-exported internal types causing type portability problems. - Workarounds suggested include explicit type annotations or disabling declaration generation. - Other users confirmed the problem persists in v1.4 beta, especially with Zod 3, but switching to Zod 4 temporarily resolves it. - Maintainers are aware and investigating fixes for future releases. **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, I will automatically close this issue in 7 days. Thank you for your understanding and contribution!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#18940