[GH-ISSUE #6440] Cannot access user.stripeCustomerId #10515

Closed
opened 2026-04-13 06:42:45 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @Lqm1 on GitHub (Dec 1, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6440

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

1, Setting Up Better-Auth on 1.3.3 Using the Stripe Plugin
2, Update to Better-Auth 1.4.x
3, Cannot access user.stripeCustomerId

Current vs. Expected behavior

Image

When I was using Better-Auth 1.3.x, I was able to access it correctly, but after updating to Better-Auth 1.4.x, I started getting type errors.

What version of Better Auth are you using?

1.4.4

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Home",
    "release": "10.0.26200",
    "cpuCount": 24,
    "cpuModel": "Intel(R) Core(TM) i7-14650HX",
    "totalMemory": "47.71 GB",
    "freeMemory": "18.90 GB"
  },
  "node": {
    "version": "v24.11.1",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.3.3"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "15.5.6"
    },
    {
      "name": "react",
      "version": "^19.0.0"
    },
    {
      "name": "hono",
      "version": "^4.8.2"
    }
  ],
  "databases": [
    {
      "name": "@prisma/client",
      "version": "^7.0.0"
    }
  ],
  "betterAuth": {
    "version": "^1.4.4",
    "config": {
      "account": {
        "accountLinking": {
          "allowDifferentEmails": true
        }
      },
      "databaseHooks": {
        "user": {
          "create": {}
        }
      },
      "emailAndPassword": {
        "enabled": true
      },
      "emailVerification": {
        "sendOnSignUp": 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
                  }
                }
              }
            }
          }
        },
        {
          "name": "captcha",
          "config": {
            "id": "captcha"
          }
        },
        {
          "name": "chatwoot",
          "config": {
            "id": "chatwoot",
            "schema": {
              "user": {
                "fields": {
                  "chatwootSourceId": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            }
          }
        },
        {
          "name": "haveIBeenPwned",
          "config": {
            "id": "haveIBeenPwned",
            "$ERROR_CODES": {
              "PASSWORD_COMPROMISED": "The password you entered has been compromised. Please choose a different password."
            }
          }
        },
        {
          "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
                  }
                }
              }
            },
            "$ERROR_CODES": {
              "SUBSCRIPTION_NOT_FOUND": "Subscription not found",
              "SUBSCRIPTION_PLAN_NOT_FOUND": "Subscription plan not found",
              "ALREADY_SUBSCRIBED_PLAN": "You're already subscribed to this plan",
              "UNABLE_TO_CREATE_CUSTOMER": "Unable to create customer",
              "FAILED_TO_FETCH_PLANS": "Failed to fetch plans",
              "EMAIL_VERIFICATION_REQUIRED": "Email verification is required before you can subscribe to a plan",
              "SUBSCRIPTION_NOT_ACTIVE": "Subscription is not active",
              "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION": "Subscription is not scheduled for cancellation"
            }
          }
        },
        {
          "name": "generic-oauth",
          "config": {
            "id": "generic-oauth",
            "endpoints": {},
            "$ERROR_CODES": {
              "INVALID_OAUTH_CONFIGURATION": "Invalid OAuth configuration",
              "TOKEN_URL_NOT_FOUND": "Invalid OAuth configuration. Token URL not found.",
              "PROVIDER_CONFIG_NOT_FOUND": "No config found for provider",
              "PROVIDER_ID_REQUIRED": "Provider ID is required",
              "INVALID_OAUTH_CONFIG": "Invalid OAuth configuration.",
              "SESSION_REQUIRED": "Session is required"
            }
          }
        },
        {
          "name": "custom-session",
          "config": {
            "id": "custom-session",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$Infer": {
              "Session": {}
            }
          }
        }
      ]
    }
  }
}

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

Backend, Client, Types

Auth config (if applicable)

import { stripe } from "@better-auth/stripe";
import { type BetterAuthOptions, betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { APIError } from "better-auth/api";
import {
	admin,
	captcha,
	customSession,
	genericOAuth,
	haveIBeenPwned,
} from "better-auth/plugins";
import { env } from "@/env";
import { chatwoot as chatwootClient } from "./chatwoot";
import { chatwoot } from "./chatwoot-plugin";
import { prisma as prismaClient } from "./prisma";
import { stripe as stripeClient } from "./stripe";

const DISPOSABLE_EMAIL_DOMAINS = [];

const FREE_EMAIL_DOMAINS = [];

const options = {
	account: {
		accountLinking: {
			allowDifferentEmails: true,
		},
	},
	database: prismaAdapter(prismaClient, {
		provider: "postgresql",
	}),
	databaseHooks: {
		user: {
			create: {
				before: async (user) => {
					const [localPart, domainPart] = user.email.split("@");
					if (!localPart || !domainPart) {
						throw new APIError("BAD_REQUEST", {
							code: "INVALID_EMAIL",
							message: "Invalid email",
						});
					}
					if (DISPOSABLE_EMAIL_DOMAINS.includes(domainPart)) {
						throw new APIError("UNPROCESSABLE_ENTITY", {
							code: "DISPOSABLE_EMAIL",
							message: "Disposable email addresses are not allowed",
						});
					}
					if (FREE_EMAIL_DOMAINS.includes(domainPart)) {
						throw new APIError("UNPROCESSABLE_ENTITY", {
							code: "FREE_EMAIL",
							message: "Free email addresses are not allowed",
						});
					}
				},
			},
		},
	},
	emailAndPassword: {
		enabled: true,
		sendResetPassword: async ({ user, url }) => {
			//
		},
	},
	emailVerification: {
		sendOnSignUp: true,
		sendVerificationEmail: async ({ user, url }) => {
			//
		},
	},
	plugins: [
		admin(),
		captcha({
			provider: "cloudflare-turnstile",
			secretKey: env.TURNSTILE_SECRET_KEY,
		}),
		chatwoot({
			chatwootClient,
			createContactOnSignUp: true,
		}),
		haveIBeenPwned(),
		stripe({
			stripeClient,
			stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
			createCustomerOnSignUp: true,
			createCustomerOnSignIn: true,
			subscription: {
				enabled: true,
				plans: [
					//
				],
			},
		}),
		genericOAuth({
			config: [
				//
			],
		}),
	],
} satisfies BetterAuthOptions;

export const auth = betterAuth({
	...options,
	plugins: [
		...(options.plugins ?? []),
		customSession(async ({ user, session }) => {
			const preference = {};
			return {
				user: { ...user, ...preference },
				session,
			};
		}, options),
	],
});

Additional context

No response

Originally created by @Lqm1 on GitHub (Dec 1, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6440 Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1, Setting Up Better-Auth on 1.3.3 Using the Stripe Plugin 2, Update to Better-Auth 1.4.x 3, Cannot access user.stripeCustomerId ### Current vs. Expected behavior <img width="950" height="178" alt="Image" src="https://github.com/user-attachments/assets/5567da02-7b57-467e-930d-4de9ea367af2" /> When I was using Better-Auth 1.3.x, I was able to access it correctly, but after updating to Better-Auth 1.4.x, I started getting type errors. ### What version of Better Auth are you using? 1.4.4 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Home", "release": "10.0.26200", "cpuCount": 24, "cpuModel": "Intel(R) Core(TM) i7-14650HX", "totalMemory": "47.71 GB", "freeMemory": "18.90 GB" }, "node": { "version": "v24.11.1", "env": "development" }, "packageManager": { "name": "bun", "version": "1.3.3" }, "frameworks": [ { "name": "next", "version": "15.5.6" }, { "name": "react", "version": "^19.0.0" }, { "name": "hono", "version": "^4.8.2" } ], "databases": [ { "name": "@prisma/client", "version": "^7.0.0" } ], "betterAuth": { "version": "^1.4.4", "config": { "account": { "accountLinking": { "allowDifferentEmails": true } }, "databaseHooks": { "user": { "create": {} } }, "emailAndPassword": { "enabled": true }, "emailVerification": { "sendOnSignUp": 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 } } } } } }, { "name": "captcha", "config": { "id": "captcha" } }, { "name": "chatwoot", "config": { "id": "chatwoot", "schema": { "user": { "fields": { "chatwootSourceId": { "type": "string", "required": false } } } } } }, { "name": "haveIBeenPwned", "config": { "id": "haveIBeenPwned", "$ERROR_CODES": { "PASSWORD_COMPROMISED": "The password you entered has been compromised. Please choose a different password." } } }, { "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 } } } }, "$ERROR_CODES": { "SUBSCRIPTION_NOT_FOUND": "Subscription not found", "SUBSCRIPTION_PLAN_NOT_FOUND": "Subscription plan not found", "ALREADY_SUBSCRIBED_PLAN": "You're already subscribed to this plan", "UNABLE_TO_CREATE_CUSTOMER": "Unable to create customer", "FAILED_TO_FETCH_PLANS": "Failed to fetch plans", "EMAIL_VERIFICATION_REQUIRED": "Email verification is required before you can subscribe to a plan", "SUBSCRIPTION_NOT_ACTIVE": "Subscription is not active", "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION": "Subscription is not scheduled for cancellation" } } }, { "name": "generic-oauth", "config": { "id": "generic-oauth", "endpoints": {}, "$ERROR_CODES": { "INVALID_OAUTH_CONFIGURATION": "Invalid OAuth configuration", "TOKEN_URL_NOT_FOUND": "Invalid OAuth configuration. Token URL not found.", "PROVIDER_CONFIG_NOT_FOUND": "No config found for provider", "PROVIDER_ID_REQUIRED": "Provider ID is required", "INVALID_OAUTH_CONFIG": "Invalid OAuth configuration.", "SESSION_REQUIRED": "Session is required" } } }, { "name": "custom-session", "config": { "id": "custom-session", "hooks": { "after": [ {} ] }, "endpoints": {}, "$Infer": { "Session": {} } } } ] } } } ``` ### Which area(s) are affected? (Select all that apply) Backend, Client, Types ### Auth config (if applicable) ```typescript import { stripe } from "@better-auth/stripe"; import { type BetterAuthOptions, betterAuth } from "better-auth"; import { prismaAdapter } from "better-auth/adapters/prisma"; import { APIError } from "better-auth/api"; import { admin, captcha, customSession, genericOAuth, haveIBeenPwned, } from "better-auth/plugins"; import { env } from "@/env"; import { chatwoot as chatwootClient } from "./chatwoot"; import { chatwoot } from "./chatwoot-plugin"; import { prisma as prismaClient } from "./prisma"; import { stripe as stripeClient } from "./stripe"; const DISPOSABLE_EMAIL_DOMAINS = []; const FREE_EMAIL_DOMAINS = []; const options = { account: { accountLinking: { allowDifferentEmails: true, }, }, database: prismaAdapter(prismaClient, { provider: "postgresql", }), databaseHooks: { user: { create: { before: async (user) => { const [localPart, domainPart] = user.email.split("@"); if (!localPart || !domainPart) { throw new APIError("BAD_REQUEST", { code: "INVALID_EMAIL", message: "Invalid email", }); } if (DISPOSABLE_EMAIL_DOMAINS.includes(domainPart)) { throw new APIError("UNPROCESSABLE_ENTITY", { code: "DISPOSABLE_EMAIL", message: "Disposable email addresses are not allowed", }); } if (FREE_EMAIL_DOMAINS.includes(domainPart)) { throw new APIError("UNPROCESSABLE_ENTITY", { code: "FREE_EMAIL", message: "Free email addresses are not allowed", }); } }, }, }, }, emailAndPassword: { enabled: true, sendResetPassword: async ({ user, url }) => { // }, }, emailVerification: { sendOnSignUp: true, sendVerificationEmail: async ({ user, url }) => { // }, }, plugins: [ admin(), captcha({ provider: "cloudflare-turnstile", secretKey: env.TURNSTILE_SECRET_KEY, }), chatwoot({ chatwootClient, createContactOnSignUp: true, }), haveIBeenPwned(), stripe({ stripeClient, stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET, createCustomerOnSignUp: true, createCustomerOnSignIn: true, subscription: { enabled: true, plans: [ // ], }, }), genericOAuth({ config: [ // ], }), ], } satisfies BetterAuthOptions; export const auth = betterAuth({ ...options, plugins: [ ...(options.plugins ?? []), customSession(async ({ user, session }) => { const preference = {}; return { user: { ...user, ...preference }, session, }; }, options), ], }); ``` ### Additional context _No response_
GiteaMirror added the locked label 2026-04-13 06:42:45 -05:00
Author
Owner

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

Hi there, thanks for opening this issue! It appears that after updating to 1.4.x users are now encountering type errors when accessing user.stripeCustomerId. In version 1.4.x some internal changes have affected how additional fields from plugins (like stripeCustomerId) are merged into the overall user type. Here are a few troubleshooting steps you might consider:

• Ensure that your stripe plugin configuration is correctly merged with your overall auth configuration. The stripe plugin adds the stripeCustomerId field to your user schema, so double-check that there aren’t conflicting type definitions elsewhere in your setup.

• If you’re explicitly typing your user object or using TypeScript inference, you might need to extend or augment the inferred types to include the stripeCustomerId property. This can be done by leveraging your adapter’s type helpers or manually merging the type, as illustrated in our documentation for extending additional fields.

• Lastly, consider verifying that you’re not accidentally overriding the user type in any custom hooks or database adapters. If this persists, you might need to cast your user object or explicitly annotate it with the expected extended type.

These steps should help align your type definitions with the new plugin schema changes. Tag @better-auth-agent if you would like an answer from the Agent.

Is there any additional context or specific error message you’re seeing that might help narrow down the issue further?

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

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3594612000 --> @better-auth-agent[bot] commented on GitHub (Dec 1, 2025): Hi there, thanks for opening this issue! It appears that after updating to 1.4.x users are now encountering type errors when accessing user.stripeCustomerId. In version 1.4.x some internal changes have affected how additional fields from plugins (like stripeCustomerId) are merged into the overall user type. Here are a few troubleshooting steps you might consider: • Ensure that your stripe plugin configuration is correctly merged with your overall auth configuration. The stripe plugin adds the stripeCustomerId field to your user schema, so double-check that there aren’t conflicting type definitions elsewhere in your setup. • If you’re explicitly typing your user object or using TypeScript inference, you might need to extend or augment the inferred types to include the stripeCustomerId property. This can be done by leveraging your adapter’s type helpers or manually merging the type, as illustrated in our documentation for extending additional fields. • Lastly, consider verifying that you’re not accidentally overriding the user type in any custom hooks or database adapters. If this persists, you might need to cast your user object or explicitly annotate it with the expected extended type. These steps should help align your type definitions with the new plugin schema changes. Tag @better-auth-agent if you would like an answer from the Agent. Is there any additional context or specific error message you’re seeing that might help narrow down the issue further? _If you need more help, tag @Skyvern in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@himself65 commented on GitHub (Jan 3, 2026):

This appears to be a type issue because we changed stripeCustomerId to optional.

/cc @bytaesu please confirm it

<!-- gh-comment-id:3706919250 --> @himself65 commented on GitHub (Jan 3, 2026): This appears to be a type issue because we changed `stripeCustomerId` to optional. /cc @bytaesu please confirm it
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10515