1use std::num::ParseIntError;
2
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6use crate::params::to_snakecase;
7
8#[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#[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#[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#[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 #[serde(skip_deserializing)]
170 pub http_status: u16,
171
172 #[serde(rename = "type")]
174 pub error_type: ErrorType,
175
176 #[serde(default)]
179 pub message: Option<String>,
180
181 pub code: Option<ErrorCode>,
183
184 pub decline_code: Option<String>,
187
188 pub charge: Option<String>,
190}
191
192#[derive(Deserialize)]
195pub struct ErrorResponse {
196 pub error: RequestError,
197}
198
199#[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}