pub mod customers_error_response; pub mod error_handlers; pub mod transformers; #[cfg(feature = "olap")] pub mod user; pub mod utils; use std::fmt::Display; pub use ::payment_methods::core::errors::VaultError; use actix_web::{body::BoxBody, ResponseError}; pub use common_utils::errors::{CustomResult, ParsingError, ValidationError}; use diesel_models::errors as storage_errors; pub use hyperswitch_domain_models::errors::api_error_response::{ ApiErrorResponse, ErrorType, NotImplementedMessage, }; pub use hyperswitch_interfaces::errors::ConnectorError; pub use redis_interface::errors::RedisError; use scheduler::errors as sch_errors; use storage_impl::errors as storage_impl_errors; #[cfg(feature = "olap")] pub use user::*; pub use self::{ customers_error_response::CustomersErrorResponse, sch_errors::*, storage_errors::*, storage_impl_errors::*, utils::{ConnectorErrorExt, StorageErrorExt}, }; use crate::services; pub type RouterResult = CustomResult; pub type RouterResponse = CustomResult, ApiErrorResponse>; pub type ApplicationResult = error_stack::Result; pub type ApplicationResponse = ApplicationResult>; pub type CustomerResponse = CustomResult, CustomersErrorResponse>; macro_rules! impl_error_display { ($st: ident, $arg: tt) => { impl Display for $st { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( fmt, "{{ error_type: {:?}, error_description: {} }}", self, $arg ) } } }; } #[macro_export] macro_rules! capture_method_not_supported { ($connector:expr, $capture_method:expr) => { Err(errors::ConnectorError::NotSupported { message: format!("{} for selected payment method", $capture_method), connector: $connector, } .into()) }; ($connector:expr, $capture_method:expr, $payment_method_type:expr) => { Err(errors::ConnectorError::NotSupported { message: format!("{} for {}", $capture_method, $payment_method_type), connector: $connector, } .into()) }; } #[macro_export] macro_rules! unimplemented_payment_method { ($payment_method:expr, $connector:expr) => { errors::ConnectorError::NotImplemented(format!( "{} through {}", $payment_method, $connector )) }; ($payment_method:expr, $flow:expr, $connector:expr) => { errors::ConnectorError::NotImplemented(format!( "{} {} through {}", $payment_method, $flow, $connector )) }; } macro_rules! impl_error_type { ($name: ident, $arg: tt) => { #[derive(Debug)] pub struct $name; impl_error_display!($name, $arg); impl std::error::Error for $name {} }; } impl_error_type!(EncryptionError, "Encryption error"); impl From for EncryptionError { fn from(_: ring::error::Unspecified) -> Self { Self } } pub fn http_not_implemented() -> actix_web::HttpResponse { ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Default, } .error_response() } #[derive(Debug, thiserror::Error)] pub enum HealthCheckOutGoing { #[error("Outgoing call failed with error: {message}")] OutGoingFailed { message: String }, } #[derive(Debug, thiserror::Error)] pub enum AwsKmsError { #[error("Failed to base64 decode input data")] Base64DecodingFailed, #[error("Failed to AWS KMS decrypt input data")] DecryptionFailed, #[error("Missing plaintext AWS KMS decryption output")] MissingPlaintextDecryptionOutput, #[error("Failed to UTF-8 decode decryption output")] Utf8DecodingFailed, } #[derive(Debug, thiserror::Error, serde::Serialize)] pub enum WebhooksFlowError { #[error("Merchant webhook config not found")] MerchantConfigNotFound, #[error("Webhook details for merchant not configured")] MerchantWebhookDetailsNotFound, #[error("Merchant does not have a webhook URL configured")] MerchantWebhookUrlNotConfigured, #[error("Webhook event updation failed")] WebhookEventUpdationFailed, #[error("Outgoing webhook body signing failed")] OutgoingWebhookSigningFailed, #[error("Webhook api call to merchant failed")] CallToMerchantFailed, #[error("Webhook not received by merchant")] NotReceivedByMerchant, #[error("Dispute webhook status validation failed")] DisputeWebhookValidationFailed, #[error("Outgoing webhook body encoding failed")] OutgoingWebhookEncodingFailed, #[error("Failed to update outgoing webhook process tracker task")] OutgoingWebhookProcessTrackerTaskUpdateFailed, #[error("Failed to schedule retry attempt for outgoing webhook")] OutgoingWebhookRetrySchedulingFailed, #[error("Outgoing webhook response encoding failed")] OutgoingWebhookResponseEncodingFailed, } impl WebhooksFlowError { pub(crate) fn is_webhook_delivery_retryable_error(&self) -> bool { match self { Self::MerchantConfigNotFound | Self::MerchantWebhookDetailsNotFound | Self::MerchantWebhookUrlNotConfigured | Self::OutgoingWebhookResponseEncodingFailed => false, Self::WebhookEventUpdationFailed | Self::OutgoingWebhookSigningFailed | Self::CallToMerchantFailed | Self::NotReceivedByMerchant | Self::DisputeWebhookValidationFailed | Self::OutgoingWebhookEncodingFailed | Self::OutgoingWebhookProcessTrackerTaskUpdateFailed | Self::OutgoingWebhookRetrySchedulingFailed => true, } } } #[derive(Debug, thiserror::Error)] pub enum ApplePayDecryptionError { #[error("Failed to base64 decode input data")] Base64DecodingFailed, #[error("Failed to decrypt input data")] DecryptionFailed, #[error("Certificate parsing failed")] CertificateParsingFailed, #[error("Certificate parsing failed")] MissingMerchantId, #[error("Key Deserialization failure")] KeyDeserializationFailed, #[error("Failed to Derive a shared secret key")] DerivingSharedSecretKeyFailed, } #[derive(Debug, thiserror::Error)] pub enum PazeDecryptionError { #[error("Failed to base64 decode input data")] Base64DecodingFailed, #[error("Failed to decrypt input data")] DecryptionFailed, #[error("Certificate parsing failed")] CertificateParsingFailed, } #[derive(Debug, thiserror::Error)] pub enum GooglePayDecryptionError { #[error("Invalid expiration time")] InvalidExpirationTime, #[error("Failed to base64 decode input data")] Base64DecodingFailed, #[error("Failed to decrypt input data")] DecryptionFailed, #[error("Failed to deserialize input data")] DeserializationFailed, #[error("Certificate parsing failed")] CertificateParsingFailed, #[error("Key deserialization failure")] KeyDeserializationFailed, #[error("Failed to derive a shared ephemeral key")] DerivingSharedEphemeralKeyFailed, #[error("Failed to derive a shared secret key")] DerivingSharedSecretKeyFailed, #[error("Failed to parse the tag")] ParsingTagError, #[error("HMAC verification failed")] HmacVerificationFailed, #[error("Failed to derive Elliptic Curve key")] DerivingEcKeyFailed, #[error("Failed to Derive Public key")] DerivingPublicKeyFailed, #[error("Failed to Derive Elliptic Curve group")] DerivingEcGroupFailed, #[error("Failed to allocate memory for big number")] BigNumAllocationFailed, #[error("Failed to get the ECDSA signature")] EcdsaSignatureFailed, #[error("Failed to verify the signature")] SignatureVerificationFailed, #[error("Invalid signature is provided")] InvalidSignature, #[error("Failed to parse the Signed Key")] SignedKeyParsingFailure, #[error("The Signed Key is expired")] SignedKeyExpired, #[error("Failed to parse the ECDSA signature")] EcdsaSignatureParsingFailed, #[error("Invalid intermediate signature is provided")] InvalidIntermediateSignature, #[error("Invalid protocol version")] InvalidProtocolVersion, #[error("Decrypted Token has expired")] DecryptedTokenExpired, #[error("Failed to parse the given value")] ParsingFailed, } #[cfg(feature = "detailed_errors")] pub mod error_stack_parsing { #[derive(serde::Deserialize)] pub struct NestedErrorStack<'a> { context: std::borrow::Cow<'a, str>, attachments: Vec>, sources: Vec>, } #[derive(serde::Serialize, Debug)] struct LinearErrorStack<'a> { context: std::borrow::Cow<'a, str>, #[serde(skip_serializing_if = "Vec::is_empty")] attachments: Vec>, } #[derive(serde::Serialize, Debug)] pub struct VecLinearErrorStack<'a>(Vec>); impl<'a> From>> for VecLinearErrorStack<'a> { fn from(value: Vec>) -> Self { let multi_layered_errors: Vec<_> = value .into_iter() .flat_map(|current_error| { [LinearErrorStack { context: current_error.context, attachments: current_error.attachments, }] .into_iter() .chain(Into::>::into(current_error.sources).0) }) .collect(); Self(multi_layered_errors) } } } #[cfg(feature = "detailed_errors")] pub use error_stack_parsing::*; #[derive(Debug, Clone, thiserror::Error)] pub enum RoutingError { #[error("Merchant routing algorithm not found in cache")] CacheMiss, #[error("Final connector selection failed")] ConnectorSelectionFailed, #[error("[DSL] Missing required field in payment data: '{field_name}'")] DslMissingRequiredField { field_name: String }, #[error("The lock on the DSL cache is most probably poisoned")] DslCachePoisoned, #[error("Expected DSL to be saved in DB but did not find")] DslMissingInDb, #[error("Unable to parse DSL from JSON")] DslParsingError, #[error("Failed to initialize DSL backend")] DslBackendInitError, #[error("Error updating merchant with latest dsl cache contents")] DslMerchantUpdateError, #[error("Error executing the DSL")] DslExecutionError, #[error("Final connector selection failed")] DslFinalConnectorSelectionFailed, #[error("[DSL] Received incorrect selection algorithm as DSL output")] DslIncorrectSelectionAlgorithm, #[error("there was an error saving/retrieving values from the kgraph cache")] KgraphCacheFailure, #[error("failed to refresh the kgraph cache")] KgraphCacheRefreshFailed, #[error("there was an error during the kgraph analysis phase")] KgraphAnalysisError, #[error("'profile_id' was not provided")] ProfileIdMissing, #[error("the profile was not found in the database")] ProfileNotFound, #[error("failed to fetch the fallback config for the merchant")] FallbackConfigFetchFailed, #[error("Invalid connector name received: '{0}'")] InvalidConnectorName(String), #[error("The routing algorithm in merchant account had invalid structure")] InvalidRoutingAlgorithmStructure, #[error("Volume split failed")] VolumeSplitFailed, #[error("Unable to parse metadata")] MetadataParsingError, #[error("Unable to retrieve success based routing config")] SuccessBasedRoutingConfigError, #[error("Params not found in success based routing config")] SuccessBasedRoutingParamsNotFoundError, #[error("Unable to calculate success based routing config from dynamic routing service")] SuccessRateCalculationError, #[error("Success rate client from dynamic routing gRPC service not initialized")] SuccessRateClientInitializationError, #[error("Elimination client from dynamic routing gRPC service not initialized")] EliminationClientInitializationError, #[error("Unable to analyze elimination routing config from dynamic routing service")] EliminationRoutingCalculationError, #[error("Params not found in elimination based routing config")] EliminationBasedRoutingParamsNotFoundError, #[error("Unable to retrieve elimination based routing config")] EliminationRoutingConfigError, #[error( "Invalid elimination based connector label received from dynamic routing service: '{0}'" )] InvalidEliminationBasedConnectorLabel(String), #[error("Unable to convert from '{from}' to '{to}'")] GenericConversionError { from: String, to: String }, #[error("Invalid success based connector label received from dynamic routing service: '{0}'")] InvalidSuccessBasedConnectorLabel(String), #[error("unable to find '{field}'")] GenericNotFoundError { field: String }, #[error("Unable to deserialize from '{from}' to '{to}'")] DeserializationError { from: String, to: String }, #[error("Unable to retrieve contract based routing config")] ContractBasedRoutingConfigError, #[error("Params not found in contract based routing config")] ContractBasedRoutingParamsNotFoundError, #[error("Unable to calculate contract score from dynamic routing service: '{err}'")] ContractScoreCalculationError { err: String }, #[error("Unable to update contract score on dynamic routing service")] ContractScoreUpdationError, #[error("contract routing client from dynamic routing gRPC service not initialized")] ContractRoutingClientInitializationError, #[error("Invalid contract based connector label received from dynamic routing service: '{0}'")] InvalidContractBasedConnectorLabel(String), #[error("Failed to perform routing in open_router")] OpenRouterCallFailed, #[error("Error from open_router: {0}")] OpenRouterError(String), } #[derive(Debug, Clone, thiserror::Error)] pub enum ConditionalConfigError { #[error("failed to fetch the fallback config for the merchant")] FallbackConfigFetchFailed, #[error("The lock on the DSL cache is most probably poisoned")] DslCachePoisoned, #[error("Merchant routing algorithm not found in cache")] CacheMiss, #[error("Expected DSL to be saved in DB but did not find")] DslMissingInDb, #[error("Unable to parse DSL from JSON")] DslParsingError, #[error("Failed to initialize DSL backend")] DslBackendInitError, #[error("Error executing the DSL")] DslExecutionError, #[error("Error constructing the Input")] InputConstructionError, } #[derive(Debug, thiserror::Error)] pub enum NetworkTokenizationError { #[error("Failed to save network token in vault")] SaveNetworkTokenFailed, #[error("Failed to fetch network token details from vault")] FetchNetworkTokenFailed, #[error("Failed to encode network token vault request")] RequestEncodingFailed, #[error("Failed to deserialize network token service response")] ResponseDeserializationFailed, #[error("Failed to delete network token")] DeleteNetworkTokenFailed, #[error("Network token service not configured")] NetworkTokenizationServiceNotConfigured, #[error("Failed while calling Network Token Service API")] ApiError, #[error("Network Tokenization is not enabled for profile")] NetworkTokenizationNotEnabledForProfile, #[error("Network Tokenization is not supported for {message}")] NotSupported { message: String }, #[error("Failed to encrypt the NetworkToken payment method details")] NetworkTokenDetailsEncryptionFailed, } #[derive(Debug, thiserror::Error)] pub enum BulkNetworkTokenizationError { #[error("Failed to validate card details")] CardValidationFailed, #[error("Failed to validate payment method details")] PaymentMethodValidationFailed, #[error("Failed to assign a customer to the card")] CustomerAssignmentFailed, #[error("Failed to perform BIN lookup for the card")] BinLookupFailed, #[error("Failed to tokenize the card details with the network")] NetworkTokenizationFailed, #[error("Failed to store the card details in locker")] VaultSaveFailed, #[error("Failed to create a payment method entry")] PaymentMethodCreationFailed, #[error("Failed to update the payment method")] PaymentMethodUpdationFailed, } #[cfg(all(feature = "revenue_recovery", feature = "v2"))] #[derive(Debug, thiserror::Error)] pub enum RevenueRecoveryError { #[error("Failed to fetch payment intent")] PaymentIntentFetchFailed, #[error("Failed to fetch payment attempt")] PaymentAttemptFetchFailed, #[error("Failed to fetch payment attempt")] PaymentAttemptIdNotFound, #[error("Failed to get revenue recovery invoice webhook")] InvoiceWebhookProcessingFailed, #[error("Failed to get revenue recovery invoice transaction")] TransactionWebhookProcessingFailed, #[error("Failed to create payment intent")] PaymentIntentCreateFailed, #[error("Source verification failed for billing connector")] WebhookAuthenticationFailed, #[error("Payment merchant connector account not found using account reference id")] PaymentMerchantConnectorAccountNotFound, #[error("Failed to fetch primitive date_time")] ScheduleTimeFetchFailed, #[error("Failed to create process tracker")] ProcessTrackerCreationError, #[error("Failed to get the response from process tracker")] ProcessTrackerResponseError, #[error("Billing connector psync call failed")] BillingConnectorPaymentsSyncFailed, #[error("Billing connector invoice sync call failed")] BillingConnectorInvoiceSyncFailed, #[error("Failed to get the retry count for payment intent")] RetryCountFetchFailed, #[error("Failed to get the billing threshold retry count")] BillingThresholdRetryCountFetchFailed, #[error("Failed to get the retry algorithm type")] RetryAlgorithmTypeNotFound, #[error("Failed to update the retry algorithm type")] RetryAlgorithmUpdationFailed, #[error("Failed to create the revenue recovery attempt data")] RevenueRecoveryAttemptDataCreateFailed, }