Diagnostic guide
duplicate stripe subscriptions for one customer
Checkout has no memory of what the customer already has unless you give it one. Without an explicit check beforehand, a slow page, a double click, or an upgrade flow that starts a new subscription instead of changing the old one will all quietly produce a second bill for the same person.
most likely causes, in order
01The checkout button has no idea the customer already subscribed+
how it looks
It usually happens right after signup: a slow page, a double click, or the back button lands the customer on checkout a second time, and both attempts succeed.
how to check
Look at what runs before a Checkout Session is created. If it does not check the customer's existing subscriptions, or your own access column, first, there is nothing stopping a second one.
the fix
Before creating a session, check whether the user already has access or an active Stripe subscription. If they do, send them to the Stripe customer portal to manage the existing plan instead.
02An upgrade flow creates a new subscription instead of changing the existing one+
how it looks
Customers who upgrade end up with two subscriptions: the old plan, still running, and the new one, both billing.
how to check
Search for where the upgrade button calls Stripe. If it creates a fresh Checkout Session rather than updating the existing subscription's items, the old one is never touched.
the fix
Update the existing subscription's price directly (or use the Stripe-hosted portal's built-in plan-switch), instead of starting a second subscription.
03The checkout button can be clicked more than once before the redirect happens+
how it looks
Reproduces specifically on a slow connection, rare on a fast one, which is why it is easy to miss in testing.
how to check
Click the button, then click it again immediately, with the network throttled. If a second session starts, the button has no disabled state.
the fix
Disable the button, or show a loading state, the instant it is clicked, until the redirect actually happens.
04Two products were bought on purpose, and this is not a bug+
how it looks
The "duplicate" is a customer who genuinely bought two different things: an add-on, a second seat block, a separate product.
how to check
Open the customer in Stripe and look at what each subscription actually contains. Two subscriptions to the same price is almost always accidental; two to different products often is not.
the fix
Nothing to fix. This is the one case worth marking as expected rather than chasing.
what this does not tell you
This is invisible from your own database by definition: your access column only knows a customer is active, not how many subscriptions produced that. The count only exists on Stripe's side, which is why finding it means comparing against Stripe directly rather than querying your own table.
Read-only, both sides. Three findings free, no account.
related
Stripe plan upgrade not updating in app
Someone paid more, or less, and your app still shows their old plan. Where the write is supposed to happen on an upgrade, and the two ways it usually goes missing.
Customer paid but has no access
Someone paid and got nothing. Fix the one in front of you in five minutes, then find out how many others are in the same state.