#[non_exhaustive]pub enum ErrorKind {
Auth,
InvalidRequest,
Declined,
NotFound,
RateLimited,
Transport,
Malformed,
Untrusted,
Unsupported,
Provider,
}Expand description
What went wrong, in terms a caller can branch on without knowing the provider.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Auth
Credentials were missing, wrong, or not allowed to do this.
InvalidRequest
The request was rejected before it reached the card network.
Declined
The bank or the network refused the payment.
NotFound
The payment was not found, or no longer exists.
RateLimited
The provider asked us to slow down.
Transport
The request never got a usable answer: DNS, TLS, timeout, socket.
Malformed
The provider answered, but with something this crate cannot read.
Untrusted
The answer could not be shown to have come from the provider.
A signature that does not match, or one that is missing where the provider always sends it. Not a transport failure and not a decline: it means the message may not be theirs, and it must never be acted on.
Unsupported
The provider does not offer what was asked of it.
Provider
The provider failed on its own side.
Implementations§
Source§impl ErrorKind
impl ErrorKind
Sourcepub const fn is_retryable(self) -> bool
pub const fn is_retryable(self) -> bool
Whether replaying the same request unchanged could plausibly succeed.
§This does not mean the retry is safe
It says the failure was not a verdict. It says nothing about whether the first attempt took the money — a timeout is exactly the case where nobody knows.
Replaying a charge is safe only where the provider offers idempotency, and not every one does:
| replaying a charge | |
|---|---|
| Stripe | safe — ChargeRequest::idempotency_key is sent as Idempotency-Key |
| iyzico | not documented safe — it refuses an idempotency key, and does not say what a reused orderId does |
| PayTR | not documented safe — no idempotency mechanism is documented for opening a payment |
| Mollie | safe — ChargeRequest::idempotency_key is sent as Idempotency-Key, and Mollie replays the first answer for an hour |
| PayPal | safe — ChargeRequest::idempotency_key is sent as PayPal-Request-Id, and PayPal returns the first answer for a repeated key |
Where it is not safe, read the payment back before sending it again.
Reading is always safe — but which call reads it back depends on what
you still have. A charge that answered and then failed later leaves a
Charge::id, and
Provider::charge_status takes it. A
charge whose answer never arrived leaves nothing but the order
reference, and that is
Provider::lookup — which is exactly the
timeout case, and exactly the two providers whose replay is not
documented as safe: iyzico and PayTR can both be asked.
Replaying a capture is a narrower question, because a capture takes
money rather than opening a request for it.
Provider::capture carries its own
idempotency, and what a timeout means depends on whether one was
sent:
| replaying a capture, with a key | replaying a capture, without one | |
|---|---|---|
| Stripe | safe — sent as Idempotency-Key, same as a charge | not safe — a second PaymentIntent capture can take the funds twice |
| iyzico | n/a — a key is refused outright, because iyzico accepts none | not safe — classic’s capture is /payment/postauth, and iyzico documents no idempotency mechanism for it |
| PayTR | n/a — no capture step; the hosted form takes the money as it goes | n/a |
| Mollie | safe — sent as Idempotency-Key on the captures endpoint, answered from the cache for an hour | not safe — a second capture against the same authorisation can take the funds twice |
| PayPal | safe — sent as PayPal-Request-Id, same as opening an order | not safe, and PayPal documents it — a second capture of the same order can take the funds twice |
Where it is not safe, this table’s answer does not change: read the
payment back with
Provider::charge_status rather
than sending Provider::capture again. A
capture whose outcome is_retryable does not resolve is read back,
never resent — with a key, resending is safe but reading is still
simpler and costs nothing extra.