Sign in

expired_card: what this Stripe decline means and why retrying it does nothing

Request a new cardlane: request_updateexpired_card
Stripe’s description

The card has expired. Stripe's suggested next step is for the customer to use another card.

What it means

The issuer says the card is past its expiry date, or that the credentials you sent belong to a card it has since replaced. On the networks this is response code 54. It is one of the few declines that is final for the details you hold: nothing about the customer's balance or standing is involved, and no amount of waiting changes the answer. Whatever card the customer is now holding, the details you stored are the ones the issuer has stopped accepting.

There are two ways to get here. The obvious one is that the expiry date you stored has passed and nobody gave you the replacement. The less obvious one is that the issuer retired the card early: a lost-card replacement, a bank rebrand, a product change, a portfolio migration after a merger. Some issuers report the old card as expired rather than invalid in that situation, which means the date on file can be years in the future and you still get 54. Your support team will assume the customer is confused. The customer, holding a card that plainly hasn't expired, will assume you are.

Stripe works with the card networks to refresh saved card details when an issuer replaces a card, and applies the new number or expiry to the stored payment method without anyone doing anything. Coverage depends on the issuer participating: it is broad for cards issued in the United States and patchy elsewhere, and Stripe's docs are explicit that you can't tell in advance which cards are covered. So an expired_card on a subscription renewal usually means the updater had nothing for this card: the issuer isn't in the programme, the region isn't covered, the account was closed rather than renewed, or the replacement hadn't been issued yet. When an update does happen, Stripe emits a payment_method.automatically_updated event.

In Stripe this decline gets its own top-level error code, expired_card, rather than the card_declined that most issuer declines arrive under, and outcome.reason on the Charge carries the same value. A handler that switches on the error code and only expects card_declined lets this one fall through.

Why it happens

  1. Date passed, no replacement on file

    The card was renewed on schedule, the new one is in the customer's wallet, and nobody told you. This is the plain case, and the one automatic card updates exist to catch.

  2. Card reissued early

    The card was replaced after loss or theft, or the bank rebranded, merged, or moved the customer to a different card product. The old credentials are dead even though the date on file looks fine.

  3. Issuer not in the updater programme

    Automatic card updates need the issuer to participate. Where it doesn't, or where the region isn't covered, expiry is handled the old way: the card fails and the customer has to act.

  4. Account closed

    The customer switched banks or closed the card. No replacement is coming from anywhere, and a request to the customer is the only route back.

  5. Wrong date at entry

    Stripe rejects an expiry that is already in the past when a card is saved, but it can't tell whether 03/28 should have been 03/30. A mistyped date works fine until the wrong month arrives.

Common mistakes

  • Retrying it

    The date doesn't move backwards. Every reattempt is a guaranteed decline that still counts against the per-card reattempt limits Visa and Mastercard enforce, and enough of them will have Stripe refusing further attempts on the card for a while, with a card_decline_rate_limit_exceeded error.

  • Asking only for a new expiry date

    A renewed card usually carries a new CVC and sometimes a new number. A form that asks the customer to correct the date sends them hunting for a two-digit change that isn't the fix. Ask for the whole card.

  • Waiting for the decline

    You already know the date. It is exp_month and exp_year on the PaymentMethod, so every card that will expire before its next renewal can be found in advance. Anything triggered by the failure happens after a missed renewal and a service gap, both of which were visible well before the charge went out.

  • Telling the customer their card has expired when it hasn't

    When the issuer retired the card early, the customer is holding a card with a valid date and your email says it expired. From where they sit the email is wrong, and they will treat the rest of it as wrong too. 'Your bank reports this card as expired or replaced' is accurate in both cases and doesn't start an argument.

How Lirova handles it

Lirova routes expired_card to request_update: no retry, and an email asking the customer for a new card. The details on file will never work again, so a retry is a guaranteed failure that spends reattempt allowance for no information, and the only event that changes the outcome is the customer supplying new card details.

There is no retry schedule for this lane. The retry lanes each have their own, which differs by decline reason and is described on the pages for those codes.

FAQ

Should I retry an expired_card decline?

No. The stored card details will not start working again, and every reattempt still counts against the per-card limits the networks apply, so a retry costs an attempt and returns nothing. The only useful action is getting new card details from the customer.

Why did Stripe return expired_card when the expiry date on file hasn't passed?

Because the issuer replaced the card before that date. Lost-card replacements, rebrands and portfolio migrations all retire the old credentials early, and some issuers report the retired card as expired rather than invalid. The date you stored was right for a card that no longer exists.

Doesn't Stripe update expired cards automatically?

Often, yes. When an issuer replaces a card and takes part in the networks' update services, Stripe applies the new number or expiry to the saved payment method on its own, so many expiries never produce a decline. Participation is common for cards issued in the United States and varies elsewhere, and there is no way to tell in advance whether a given card is covered. An expired_card on a renewal usually means no update was available for that card.

What should the customer update after an expired_card decline?

The whole card. A renewed card usually has a new CVC and sometimes a new number, so a form that only takes a new expiry date will fail again. Send the customer somewhere that collects the full card details and replaces the payment method.

Can I see that a card is about to expire before the payment fails?

Yes. The card object on a PaymentMethod carries exp_month and exp_year, so you can query for cards that expire before their next renewal date and ask for an update ahead of time. Stripe's automatic updates may still fix some of them before you need to, and those show up as payment_method.automatically_updated events.

Related codes

Updated 2026-09-01