stripe/
error.rs

1use std::num::ParseIntError;
2
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6use crate::params::to_snakecase;
7
8/// An error encountered when communicating with the Stripe API.
9#[derive(Debug, Error)]
10pub enum StripeError {
11    #[error("error reported by stripe: {0}")]
12    Stripe(#[from] RequestError),
13    #[error("error serializing or deserializing a querystring: {0}")]
14    QueryStringSerialize(#[from] serde_path_to_error::Error<serde_qs::Error>),
15    #[error("error serializing or deserializing a request")]
16    JSONSerialize(#[from] serde_path_to_error::Error<serde_json::Error>),
17    #[error("attempted to access an unsupported version of the api")]
18    UnsupportedVersion,
19    #[error("error communicating with stripe: {0}")]
20    ClientError(String),
21    #[error("timeout communicating with stripe")]
22    Timeout,
23}
24
25#[cfg(feature = "hyper")]
26impl From<hyper::Error> for StripeError {
27    fn from(err: hyper::Error) -> StripeError {
28        StripeError::ClientError(err.to_string())
29    }
30}
31
32impl From<http_types::Error> for StripeError {
33    fn from(err: http_types::Error) -> StripeError {
34        StripeError::ClientError(err.to_string())
35    }
36}
37
38/// The list of possible values for a RequestError's type.
39#[derive(Debug, PartialEq, Deserialize, Default)]
40pub enum ErrorType {
41    #[serde(skip_deserializing)]
42    #[default]
43    Unknown,
44    #[serde(rename = "api_error")]
45    Api,
46    #[serde(rename = "api_connection_error")]
47    Connection,
48    #[serde(rename = "authentication_error")]
49    Authentication,
50    #[serde(rename = "card_error")]
51    Card,
52    #[serde(rename = "idempotency_error")]
53    IdempotencyError,
54    #[serde(rename = "invalid_request_error")]
55    InvalidRequest,
56    #[serde(rename = "rate_limit_error")]
57    RateLimit,
58    #[serde(rename = "validation_error")]
59    Validation,
60}
61
62impl std::fmt::Display for ErrorType {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        write!(f, "{}", to_snakecase(&format!("{:?}Error", self)))
65    }
66}
67
68/// The list of possible values for a RequestError's code.
69#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
70#[serde(rename_all = "snake_case")]
71#[non_exhaustive]
72pub enum ErrorCode {
73    AccountAlreadyExists,
74    AccountCountryInvalidAddress,
75    AccountInvalid,
76    AccountNumberInvalid,
77    AlipayUpgradeRequired,
78    AmountTooLarge,
79    AmountTooSmall,
80    ApiKeyExpired,
81    BalanceInsufficient,
82    BankAccountExists,
83    BankAccountUnusable,
84    BankAccountUnverified,
85    BankAccountVerificationFailed,
86    BitcoinUpgradeRequired,
87    CardDeclined,
88    ChargeAlreadyCaptured,
89    ChargeAlreadyRefunded,
90    ChargeDisputed,
91    ChargeExpiredForCapture,
92    CountryUnsupported,
93    CouponExpired,
94    CustomerMaxSubscriptions,
95    EmailInvalid,
96    ExpiredCard,
97    IdempotencyKeyInUse,
98    IncorrectAddress,
99    IncorrectCvc,
100    IncorrectNumber,
101    IncorrectZip,
102    InstantPayoutsUnsupported,
103    InvalidCardType,
104    InvalidChargeAmount,
105    InvalidCvc,
106    InvalidExpiryMonth,
107    InvalidExpiryYear,
108    InvalidNumber,
109    InvalidSourceUsage,
110    InvoiceNoCustomerLineItems,
111    InvoiceNoSubscriptionLineItems,
112    InvoiceNotEditable,
113    InvoiceUpcomingNone,
114    LivemodeMismatch,
115    Missing,
116    OrderCreationFailed,
117    OrderRequiredSettings,
118    OrderStatusInvalid,
119    OrderUpstreamTimeout,
120    OutOfInventory,
121    ParameterInvalidEmpty,
122    ParameterInvalidInteger,
123    ParameterInvalidStringBlank,
124    ParameterInvalidStringEmpty,
125    ParameterMissing,
126    ParameterUnknown,
127    PaymentMethodUnactivated,
128    PaymentIntentUnexpectedState,
129    PayoutsNotAllowed,
130    PlatformApiKeyExpired,
131    PostalCodeInvalid,
132    ProcessingError,
133    ProductInactive,
134    RateLimit,
135    ResourceAlreadyExists,
136    ResourceMissing,
137    RoutingNumberInvalid,
138    SecretKeyRequired,
139    SepaUnsupportedAccount,
140    ShippingCalculationFailed,
141    SkuInactive,
142    StateUnsupported,
143    TaxIdInvalid,
144    TaxesCalculationFailed,
145    TestmodeChargesOnly,
146    TlsVersionUnsupported,
147    TokenAlreadyUsed,
148    TokenInUse,
149    TransfersNotAllowed,
150    UpstreamOrderCreationFailed,
151    UrlInvalid,
152}
153
154impl std::fmt::Display for ErrorCode {
155    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156        write!(f, "{}", to_snakecase(&format!("{:?}", self)))
157    }
158}
159
160/// An error reported by stripe in a request's response.
161///
162/// For more details see <https://stripe.com/docs/api#errors>.
163#[derive(Debug, Default, Deserialize, Error)]
164#[error("{error_type} ({http_status}){}", message.as_ref().map(|msg| {
165    format!(" with message: {msg:?}")
166}).unwrap_or_default())]
167pub struct RequestError {
168    /// The HTTP status in the response.
169    #[serde(skip_deserializing)]
170    pub http_status: u16,
171
172    /// The type of error returned.
173    #[serde(rename = "type")]
174    pub error_type: ErrorType,
175
176    /// A human-readable message providing more details about the error.
177    /// For card errors, these messages can be shown to end users.
178    #[serde(default)]
179    pub message: Option<String>,
180
181    /// For card errors, a value describing the kind of card error that occured.
182    pub code: Option<ErrorCode>,
183
184    /// For card errors resulting from a bank decline, a string indicating the
185    /// bank's reason for the decline if they provide one.
186    pub decline_code: Option<String>,
187
188    /// The ID of the failed charge, if applicable.
189    pub charge: Option<String>,
190}
191
192/// The structure of the json body when an error is included in
193/// the response from Stripe.
194#[derive(Deserialize)]
195pub struct ErrorResponse {
196    pub error: RequestError,
197}
198
199/// An error encountered when communicating with the Stripe API webhooks.
200#[derive(Debug, Error)]
201pub enum WebhookError {
202    #[error("invalid key length")]
203    BadKey,
204    #[error("error parsing timestamp")]
205    BadHeader(#[from] ParseIntError),
206    #[error("error comparing signatures")]
207    BadSignature,
208    #[error("error comparing timestamps - over tolerance")]
209    BadTimestamp(i64),
210    #[error("error parsing event object")]
211    BadParse(#[from] serde_json::Error),
212}