Stripe No such customer: test/live key mismatch and the self-heal fix
Guide Stripe No such customer: test/live key mismatch and the self-heal fix: Sometimes Stripe adds the hint: "a similar object exists in test mode, but a live mode key was used to make this request." ## Confirm the cause Three usual causes, check in order: 1. Use this when you hit exactly this in Stripe No such customer. Not for different errors or different tools.
TL;DR: Sometimes Stripe adds the hint: "a similar object exists in test mode, but a live mode key was used to make this request." ## Confirm the cause Three usual causes, check in order: 1. # Stripe No such customer: test/live key mismatch and the self-heal fix ## The symptom StripeInvalidRequestError: No such customer: 'cus_...'
Stripe No such customer: test/live key mismatch and the self-heal fix
The symptom
StripeInvalidRequestError: No such customer: 'cus_...', code resource_missing, param customer, HTTP 400. Sometimes Stripe adds the hint: "a similar object exists in test mode, but a live mode key was used to make this request."
Confirm the cause
Three usual causes, check in order:
- Test/live mismatch. The id was created under
sk_testand the request usessk_live(or vice versa). Stripe objects live in exactly one mode. This is the classic post-launch bug: test-mode customer ids stored in your DB before the cutover. - Wrong account. The key belongs to a different Stripe account than the one that created the object.
- Deleted object. Someone deleted the customer in the dashboard.
Log which key prefix made the call and compare against where the id was minted.
The fix
Make checkout self-heal instead of crashing. Catch the specific error and retry once with a fresh customer:
function isStaleCustomerError(err) {
return err.code === 'resource_missing' && err.param === 'customer';
}
try {
session = await stripe.checkout.sessions.create({ customer: storedId, ... });
} catch (err) {
if (isStaleCustomerError(err)) {
const fresh = await stripe.customers.create({ email: user.email });
await db.users.update({ stripe_customer_id: fresh.id });
session = await stripe.checkout.sessions.create({ customer: fresh.id, ... });
} else throw err;
}Scope the catch narrowly: only resource_missing on the customer param. A missing price or a decline must keep failing loudly; minting a customer for those hides the real error. Retry once, not in a loop.
Also fix the root cause: make sure every Stripe env var (secret key, webhook secret, price ids) comes from the same account and mode. A mode flip orphans all three at once.
Verify the fix
In test mode, store a bogus customer id, attempt checkout, and confirm the code mints a fresh customer, persists it, and completes. Confirm a genuinely different error (bad price id) still surfaces instead of healing. After any test-to-live cutover, run one live checkout end to end before announcing.
When to use
You hit exactly this: Stripe No such customer: test/live key mismatch and the self-heal fix in Stripe No such customer.
When not to use
A different error, or the same symptom in a different tool. This page only covers the failure above.
Compatibility
Stripe No such customer.
Edge cases
- Also fix the root cause: make sure every Stripe env var (secret key, webhook secret, price ids) comes from the same account and mode.
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.