pub enum BridgeError {
SignatureError(String),
HttpError(Error),
MerchantError(String),
CryptoError(String),
InvalidMerchantUrl(String),
InvalidConsumerId(String),
ReplayAttack,
RequestTooOld(SystemTime),
RateLimitExceeded,
CircuitOpen,
}Expand description
Errors that can occur in the TAP-MCP bridge.
All variants include contextual information about what went wrong. The error messages are designed to be user-facing and actionable.
§Error Recovery
- Transient errors (
HttpError): Retry with exponential backoff - Validation errors (
InvalidMerchantUrl): Fix input and retry - Cryptographic errors (
SignatureError,CryptoError): Check key configuration - Protocol errors (
MerchantError): Contact merchant support
This type implements #[must_use] to ensure errors are not silently ignored.
Always handle errors by checking, propagating, or explicitly panicking.
Variants§
SignatureError(String)
TAP signature generation failed.
This error occurs when the bridge cannot generate a valid RFC 9421 HTTP Message Signature. Common causes include:
- Invalid signing key format
- System time errors (cannot determine signature timestamp)
- Signature base string construction failures
§Recovery
Check that the Ed25519 signing key is valid and system time is correctly set.
HttpError(Error)
HTTP request failed.
This error wraps reqwest::Error and occurs when network communication with
the merchant fails. Common causes include:
- Network timeouts (default: 30 seconds)
- Connection refused (merchant server down)
- DNS resolution failures
- TLS/SSL errors
§Recovery
Retry the request with exponential backoff. If the error persists, verify:
- Merchant URL is correct and accessible
- Network connectivity is available
- Firewall/proxy settings allow HTTPS connections
MerchantError(String)
Invalid merchant response.
This error occurs when the merchant returns a response that violates the TAP protocol. Common causes include:
- Unexpected HTTP status code
- Malformed JSON response
- Missing required fields in response
- Protocol version mismatch
§Recovery
This usually indicates a merchant-side issue. Contact the merchant to verify:
- Their TAP implementation is up to date
- The endpoint accepts the request format being sent
- Any API keys or authentication tokens are valid
CryptoError(String)
Cryptographic operation failed.
This error occurs when a low-level cryptographic operation fails. Common causes include:
- Invalid key material
- Hash computation failures
- Base64 encoding/decoding errors
§Recovery
Verify that:
- Signing keys are valid Ed25519 keys
- Key material has not been corrupted
- System has sufficient entropy for cryptographic operations
InvalidMerchantUrl(String)
Invalid merchant URL.
This error occurs when input validation rejects a merchant URL. Common causes include:
- Non-HTTPS URL (HTTP is not allowed)
- Localhost or loopback addresses (security restriction)
- Malformed URL syntax
§Recovery
Ensure the merchant URL:
- Uses HTTPS scheme (
https://) - Is not a localhost address (
localhost,127.0.0.1) - Has valid syntax per RFC 3986
§Examples
use tap_mcp_bridge::error::BridgeError;
// These URLs will be rejected:
let err = BridgeError::InvalidMerchantUrl("http://example.com".to_string());
assert!(err.to_string().contains("Invalid merchant URL"));
let err = BridgeError::InvalidMerchantUrl("https://localhost/checkout".to_string());
assert!(err.to_string().contains("Invalid merchant URL"));InvalidConsumerId(String)
Invalid consumer ID.
This error occurs when input validation rejects a consumer ID. Consumer IDs must meet these requirements:
- Not empty
- Maximum 64 characters
- Only alphanumeric characters, hyphens, and underscores
§Recovery
Ensure the consumer ID:
- Contains only letters (a-z, A-Z), numbers (0-9), hyphens (-), and underscores (_)
- Has at least 1 character
- Has no more than 64 characters
§Examples
use tap_mcp_bridge::error::BridgeError;
// These consumer IDs will be rejected:
let err = BridgeError::InvalidConsumerId("consumer@example.com".to_string());
assert!(err.to_string().contains("Invalid consumer ID"));
let err = BridgeError::InvalidConsumerId("".to_string());
assert!(err.to_string().contains("Invalid consumer ID"));ReplayAttack
Replay attack detected.
This error occurs when a request with a previously seen nonce is received within the 8-minute validity window.
RequestTooOld(SystemTime)
Request too old.
This error occurs when the request timestamp is outside the allowed window.
RateLimitExceeded
Rate limit exceeded.
This error occurs when too many requests are made in a short period.
Rate limiting protects against DoS attacks and ensures fair resource usage.
§Recovery
Wait a short period (e.g., 1 second) and retry the request. Consider implementing exponential backoff for repeated failures.
CircuitOpen
Circuit breaker is open.
This error occurs when the circuit breaker has detected too many failures and is temporarily rejecting all requests to prevent cascading failures. The circuit will automatically transition to half-open state after the reset timeout expires.
§Recovery
Wait for the circuit breaker’s reset timeout to expire (typically 60 seconds). The circuit will then allow limited test requests to determine if the underlying service has recovered.
Trait Implementations§
Source§impl Debug for BridgeError
impl Debug for BridgeError
Source§impl Display for BridgeError
impl Display for BridgeError
Source§impl Error for BridgeError
impl Error for BridgeError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
Auto Trait Implementations§
impl Freeze for BridgeError
impl !RefUnwindSafe for BridgeError
impl Send for BridgeError
impl Sync for BridgeError
impl Unpin for BridgeError
impl !UnwindSafe for BridgeError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> ToStringFallible for Twhere
T: Display,
impl<T> ToStringFallible for Twhere
T: Display,
Source§fn try_to_string(&self) -> Result<String, TryReserveError>
fn try_to_string(&self) -> Result<String, TryReserveError>
ToString::to_string, but without panic on OOM.