[Stripe] User can't update same product subscription #1500

Closed
opened 2026-03-13 08:43:33 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @FabienCoutant on GitHub (Jul 15, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

How to reproduce

  • create on stripe.com a product with monthly and yearly payment
  • init stripe plugin with this basic type of plan:
const stripePlan = [
  {   
      name: "my-product',
      priceId: "monthy_priceId",
      annualDiscountPriceId: "yearly_priceId",
      ....
  }
]
  • purchase the plan on monthly
await authClient.subscription.upgrade({
          plan,
          referenceId: subscription.referenceId,
          annual: false, 
          ...
        });
  • update the plan to yearly
await authClient.subscription.upgrade({
          plan,
          subscriptionId: subscription.stripeSubscriptionId,
          annual: true,
          ...
        });
  • you should get an error 400 with the following code: "YOURE_ALREADY_SUBSCRIBED_TO_THIS_PLAN"

Current vs. Expected behavior

Current

We can't have a single stripe product with monthly and yearly payment under it. Workaround is to create one product per type of payment (ex: my_product_monthly, my_product_yearly)

Expected

It should be possible to change the payment price under the same plan name

What version of Better Auth are you using?

1.2.12

Provide environment information

- Os: MacOs

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

Package

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

Issue coming from :
0a8c8d2bf4/packages/stripe/src/index.ts (L309)
which doesn't compare the price_idk

Maybe we should store the price_id the user subscribed or an isYearlyPayment boolean

Originally created by @FabienCoutant on GitHub (Jul 15, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce ## How to reproduce - create on stripe.com a product with monthly and yearly payment - init stripe plugin with this basic type of plan: ``` const stripePlan = [ { name: "my-product', priceId: "monthy_priceId", annualDiscountPriceId: "yearly_priceId", .... } ] ``` - purchase the plan on monthly ``` await authClient.subscription.upgrade({ plan, referenceId: subscription.referenceId, annual: false, ... }); ``` - update the plan to yearly ``` await authClient.subscription.upgrade({ plan, subscriptionId: subscription.stripeSubscriptionId, annual: true, ... }); ``` - you should get an error 400 with the following code: "YOURE_ALREADY_SUBSCRIBED_TO_THIS_PLAN" ### Current vs. Expected behavior ### Current We can't have a single stripe product with monthly and yearly payment under it. Workaround is to create one product per type of payment (ex: my_product_monthly, my_product_yearly) ### Expected It should be possible to change the payment price under the same plan name ### What version of Better Auth are you using? 1.2.12 ### Provide environment information ```bash - Os: MacOs ``` ### Which area(s) are affected? (Select all that apply) Package ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context Issue coming from : https://github.com/better-auth/better-auth/blob/0a8c8d2bf4d06548f5efa1cd4e1504bc83ad533b/packages/stripe/src/index.ts#L309 which doesn't compare the price_idk Maybe we should store the price_id the user subscribed or an isYearlyPayment boolean
Author
Owner

@dosubot[bot] commented on GitHub (Jul 15, 2025):

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

This is a known limitation in the current Better Auth Stripe integration: the duplicate subscription check only compares the plan name and seats, not the priceId, so switching between monthly and yearly prices under the same product triggers the "YOURE_ALREADY_SUBSCRIBED_TO_THIS_PLAN" error. This logic is in packages/stripe/src/index.ts and is responsible for blocking upgrades between different billing intervals of the same product [source].

How to fix:
The check should also compare the priceId. For example, you could update the logic to:

if (
  existingSubscription &&
  existingSubscription.status === "active" &&
  existingSubscription.plan === ctx.body.plan &&
  existingSubscription.seats === (ctx.body.seats || 1) &&
  existingSubscription.priceId === priceIdToUse // <-- add this line
) {
  throw new APIError("BAD_REQUEST", {
    message: STRIPE_ERROR_CODES.ALREADY_SUBSCRIBED_PLAN,
  });
}

Here, priceIdToUse should be set to the correct priceId for the intended interval (monthly/yearly) as already determined elsewhere in the upgrade logic.

Workaround:
Until this is fixed, the only workaround is to use separate Stripe products for monthly and yearly plans.

No recent pull requests address this specific logic gap, though there have been improvements to priceId handling and validation elsewhere in the codebase [source].

Let me know if you want a more detailed code snippet or guidance on where to make this change.

To reply, just mention @dosu.


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

@dosubot[bot] commented on GitHub (Jul 15, 2025): <!-- Greeting --> Hi @FabienCoutant! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known limitation in the current Better Auth Stripe integration: the duplicate subscription check only compares the plan name and seats, not the priceId, so switching between monthly and yearly prices under the same product triggers the "YOURE_ALREADY_SUBSCRIBED_TO_THIS_PLAN" error. This logic is in `packages/stripe/src/index.ts` and is responsible for blocking upgrades between different billing intervals of the same product [[source]](https://github.com/better-auth/better-auth/blob/0a8c8d2bf4d06548f5efa1cd4e1504bc83ad533b/packages/stripe/src/index.ts). **How to fix:** The check should also compare the priceId. For example, you could update the logic to: ```ts if ( existingSubscription && existingSubscription.status === "active" && existingSubscription.plan === ctx.body.plan && existingSubscription.seats === (ctx.body.seats || 1) && existingSubscription.priceId === priceIdToUse // <-- add this line ) { throw new APIError("BAD_REQUEST", { message: STRIPE_ERROR_CODES.ALREADY_SUBSCRIBED_PLAN, }); } ``` Here, `priceIdToUse` should be set to the correct priceId for the intended interval (monthly/yearly) as already determined elsewhere in the upgrade logic. **Workaround:** Until this is fixed, the only workaround is to use separate Stripe products for monthly and yearly plans. No recent pull requests address this specific logic gap, though there have been improvements to priceId handling and validation elsewhere in the codebase [[source]](https://github.com/better-auth/better-auth/pull/3239). Let me know if you want a more detailed code snippet or guidance on where to make this change. <!-- 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/66fd518d-0f46-4690-80b4-573a247e9924?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/66fd518d-0f46-4690-80b4-573a247e9924?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/66fd518d-0f46-4690-80b4-573a247e9924?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/66fd518d-0f46-4690-80b4-573a247e9924?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/66fd518d-0f46-4690-80b4-573a247e9924?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/66fd518d-0f46-4690-80b4-573a247e9924?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/66fd518d-0f46-4690-80b4-573a247e9924?feedback_type=other)</sup>&nbsp;&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/3393)
Author
Owner

@dagmawibabi commented on GitHub (Jul 16, 2025):

Hey @FabienCoutant is this the same problem as https://github.com/better-auth/better-auth/issues/3393?

@dagmawibabi commented on GitHub (Jul 16, 2025): Hey @FabienCoutant is this the same problem as https://github.com/better-auth/better-auth/issues/3393?
Author
Owner

@FabienCoutant commented on GitHub (Jul 16, 2025):

Hey @FabienCoutant is this the same problem as #3393?

hey @dagmawibabi, not sure you tagged the correct issue

@FabienCoutant commented on GitHub (Jul 16, 2025): > Hey [@FabienCoutant](https://github.com/FabienCoutant) is this the same problem as [#3393](https://github.com/better-auth/better-auth/issues/3393)? hey @dagmawibabi, not sure you tagged the correct issue
Author
Owner

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

Hi, @FabienCoutant. 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 that Better Auth v1.2.12 does not allow updating a Stripe subscription from monthly to yearly pricing under the same product, causing a "YOURE_ALREADY_SUBSCRIBED_TO_THIS_PLAN" error.
  • The root cause is that the Stripe integration compares only plan name and seats, not the priceId, which leads to this conflict.
  • A suggested fix is to update the logic to include priceId comparison to properly handle subscription updates.
  • The current workaround is to use separate Stripe products for different billing intervals.
  • Another user asked if this issue relates to #3393, but you clarified it is unrelated.

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!

@dosubot[bot] commented on GitHub (Oct 15, 2025): Hi, @FabienCoutant. 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 that Better Auth v1.2.12 does not allow updating a Stripe subscription from monthly to yearly pricing under the same product, causing a "YOURE_ALREADY_SUBSCRIBED_TO_THIS_PLAN" error. - The root cause is that the Stripe integration compares only plan name and seats, not the priceId, which leads to this conflict. - A suggested fix is to update the logic to include priceId comparison to properly handle subscription updates. - The current workaround is to use separate Stripe products for different billing intervals. - Another user asked if this issue relates to #3393, but you clarified it is unrelated. **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#1500