card_declined in Stripe: the code that tells you the real reason is somewhere else
lane: unhandledcard_declinedThe classifier names no rule of its own for this code. It is not left untouched: the general default applies, and the code is recorded as unrecognised.
The card has been declined. When a card is declined, the error also includes a decline_code attribute with the reason the card was declined.
What it means
card_declined is Stripe's wrapper for 'the issuer said no'. It is the code on the card error and the failure_code on the Charge, and on its own it tells you that the failure came from the card side rather than from a malformed request. The reason, where Stripe has one, sits next to it in decline_code: insufficient_funds, do_not_honor, lost_card, fraudulent, and the rest of Stripe's list. Most of the codes documented on this site arrived inside a card_declined error.
Not every issuer decline is wrapped this way. A few get their own top-level error code instead: expired_card, incorrect_cvc, incorrect_number and processing_error come back as themselves. Everything else lands under card_declined, which is why a handler that only checks for card_declined misses expired cards, and a handler that only reads decline_code can miss them too.
If all you have is the wrapper, one of a few things is true. You are reading a field that only carries the top-level code, such as failure_code on the Charge. The issuer declined without a usable reason, which Stripe reports as decline_code generic_decline, the actual no-information case. The payment never reached the issuer because Radar blocked it, which also comes back as card_declined, with a decline_code of fraudulent or generic_decline and outcome.type set to blocked on the Charge. Or the decline_code is right there in the same object and nobody has read it yet.
So the short answer to what card_declined means is: look at the next field. Some of the values there are safe to retry on a spaced schedule, some are prohibited by network rules, some are blocks from your own Radar rules that will repeat until the rule changes, and the wrapper doesn't say which.
Why it happens
You're reading the top-level field
failure_code on the Charge and code on the error carry card_declined and nothing else. decline_code on the same error and outcome.reason on the Charge are where the reason went.
The issuer gave no usable reason
Stripe reports this as decline_code generic_decline, and its docs say issuers categorise most declines this way, so it is the ordinary case rather than an edge case.
Radar blocked it before authorisation
The issuer never saw the payment. outcome.type on the Charge is blocked, outcome.reason gives the risk level or says rule, and outcome.rule identifies which rule. Retrying meets the same rule.
A specific reason you haven't looked at yet
Most card_declined errors carry a decline_code Stripe recognises. Two of them, insufficient_funds and do_not_honor, have their own pages here; expired_card does too, though it arrives under its own error code.
Common mistakes
One retry rule for the whole code
A handler keyed on card_declined retries lost and stolen cards on the same schedule as a customer who is short until payday. The first group cannot recover and the reattempts count against network limits anyway; the second group needs time between attempts. Route on decline_code or don't route at all.
Logging code and dropping decline_code
If your failures table has a card_declined column and nothing beside it, every decline looks identical after the fact and you can't classify or retry with any precision. Store decline_code and the outcome fields with it. They stay on the Charge object in Stripe if you ever need to backfill, but it is cheaper to capture them when they arrive.
Showing the customer more than the wrapper
'card_declined' means nothing to a customer, and a raw decline_code can mean too much: Stripe says not to disclose fraudulent, lost_card, stolen_card or merchant_blacklist and to present them as a generic decline. The message field on the error is written to be shown to customers and is safe as-is. Use decline_code on your side and the message on theirs.
Retrying a Radar block as if the issuer declined it
A block comes from your own rules, so the next attempt meets the same rule with the same result. If the rule was wrong, fix it and add the payment to your allow list; if it was right, you are retrying a payment your own fraud tooling rejected.
How Lirova handles it
The classifier names no rule for card_declined. A case that arrives with this code takes the general default, and Lirova records it as unrecognised. That's a gap, and it's listed here as one.
The rules that do exist are keyed to specific codes, including the three others on this site. Their retry schedules differ by decline reason and are described on those pages.
FAQ
What does card_declined mean in Stripe?
It is the error code Stripe uses for a decline that came from the card side, as opposed to an invalid request or a processing error. The reason is in the separate decline_code field on the same error, when the issuer provided one. On its own, card_declined tells you the category of failure and nothing about the cause.
Where do I find the actual decline reason for a card_declined error?
In decline_code on the error object, which is last_payment_error on a PaymentIntent, and in the outcome object on the Charge, where outcome.reason carries the decline code and outcome.type says whether the issuer declined or Radar blocked. The Dashboard shows the same decline code on the payment's detail page.
Is card_declined the same as generic_decline?
No. card_declined is the top-level error code and appears on most issuer declines. generic_decline is one possible decline_code beneath it, meaning the issuer gave no reason Stripe could map to anything more specific, or that Radar blocked the payment. A card_declined with decline_code insufficient_funds and one with generic_decline are completely different situations sharing a wrapper.
Should I retry a card_declined payment?
You can't answer that from the wrapper. Some decline codes underneath it are worth retrying on a spaced schedule, some are prohibited by network rules, some are blocks from your own Radar rules that will repeat, and some need the customer to do something first. Get the decline_code before deciding; retrying blind means retrying the prohibited ones too.
Why does Stripe just say 'Your card was declined' with no reason?
That is Stripe's customer-facing message for card_declined, and it is generic on purpose. The detail is kept in decline_code for you, because some reasons, such as suspected fraud or a card reported stolen, shouldn't be shown to whoever submitted the card. Show the customer the message and keep the decline_code on your side.
Related codes
Updated 2026-09-01