open-standards/openpay/crates/op-openbanking/src/error.rs
Transaction Science 6ea90afbed ingest wave A4: 3 crates · smart-byte-atproto + op-openbanking + eoc-distributed
Smart Byte (1 crate, 2127 LOC, 35 tests)
  smart-byte-atproto    ATProto (Bluesky federation) adapter.
                        PLC + did:web resolution; XRPC client; CARv1 encode/decode
                        with CIDv1 (dag-cbor + raw, SHA-256); sketch MST with
                        order-independent BLAKE3 root; Repo + UnsignedCommit /
                        SignedCommit (Ed25519 over CBOR); firehose transport
                        trait + in-memory impl; AT URI ↔ smart-byte AID bridge
                        with SAID commitment.

OpenPay (1 crate, 2397 LOC, 44 tests)
  op-openbanking        UK OBIE R/W v3.1.10/3.1.11, Berlin Group NextGenPSD2
                        XS2A v1.3.13, STET PSD2 v1.7, Australia CDR Banking v1.31,
                        FDX v5/v6, SGFinDex shapes. AISP / PISP / PIIS / VRP
                        traits. FAPI 1.0 Advanced (PS256/ES256, mTLS, RFC 8705
                        certificate binding, JWK registration). Operators wire
                        their own JWS signer + HTTP transport — keeps the crate
                        KMS-agnostic.

EOC (1 crate, 2179 LOC, 32 tests)
  eoc-distributed       Distributed-inference scheduling. Worker trait with
                        Capability + Accelerator (CPU/GPU/TPU/NPU/Mixed) +
                        Load.busyness()/projected_micro_joules()/projected_g_co2e().
                        RoundRobin / LeastBusy / LatencyWeighted / JouleWeighted
                        (default) / CarbonWeighted routers. Work-stealing
                        scheduler. vLLM-style continuous batching with KV-block
                        budget. Ray-Serve-style auto-scaler with cooldown.
                        KV-cache-aware sticky-session routing.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-24 12:22:09 -04:00

110 lines
3.8 KiB
Rust

//! Error types for `op-openbanking`.
//!
//! One sealed enum per crate convention. Adding a variant is a
//! SemVer-major change.
use thiserror::Error;
/// Result alias for `op-openbanking`.
pub type Result<T> = core::result::Result<T, Error>;
/// All possible failure modes inside `op-openbanking`.
#[derive(Debug, Error)]
pub enum Error {
/// A consent identifier was referenced but does not exist or has expired.
#[error("consent not found or expired: {0}")]
ConsentNotFound(String),
/// The consent is in a state that does not permit the requested operation.
///
/// E.g. an AISP read against a consent that is still `AwaitingAuthorisation`,
/// or a PISP execution against a `Rejected` consent.
#[error("consent state invalid: {reason}")]
ConsentStateInvalid {
/// Human-readable reason.
reason: String,
},
/// The requested scope was not granted at consent creation. UK
/// OBIE and Berlin Group both treat this as a hard 403.
#[error("scope not authorised: {0}")]
ScopeNotAuthorised(String),
/// FAPI-required header is missing (e.g. `x-fapi-interaction-id`,
/// `x-jws-signature`, `psu-id`).
#[error("FAPI header missing: {0}")]
FapiHeaderMissing(&'static str),
/// JWS request-object signature failed verification.
///
/// We do not say *which* part failed; that's a per-ASPSP audit
/// concern. Operators receive a structured trace via [`tracing`].
#[error("JWS signature verification failed")]
JwsSignatureInvalid,
/// The signer trait impl returned an upstream error (HSM offline,
/// KMS-policy denial, eIDAS card removed).
#[error("JWS signer error: {0}")]
Signer(String),
/// mTLS client-certificate binding did not match the OAuth2 token
/// (RFC 8705 § 3 certificate-bound access tokens).
#[error("certificate binding mismatch (RFC 8705)")]
CertificateBindingMismatch,
/// JWK registration / lookup failed in the operator-supplied
/// [`crate::fapi::JwkRegistration`] impl.
#[error("JWK registration error: {0}")]
JwkRegistration(String),
/// OAuth 2.0 token rejected: expired, audience mismatched, scope
/// downgraded, or simply not produced by the issuer we expect.
#[error("OAuth2 token invalid: {reason}")]
OAuth2TokenInvalid {
/// Why the token failed validation.
reason: String,
},
/// A payment-initiation payload failed validation (currency mismatch,
/// zero amount, missing remittance info on a SEPA SCT, etc.).
#[error("payment initiation invalid: {reason}")]
PaymentInitiationInvalid {
/// Why the initiation was rejected.
reason: String,
},
/// A VRP execution exceeded the consent's [`crate::vrp::VrpControlParameters`]
/// (per-payment, per-period, or aggregate cap).
#[error("VRP control parameters exceeded: {reason}")]
VrpLimitExceeded {
/// Which limit was breached.
reason: String,
},
/// The ASPSP returned a documented error that does not map to any
/// of the variants above.
#[error("ASPSP error ({code}): {reason}")]
AspspError {
/// Standard-specific code, copied verbatim.
code: String,
/// Human-readable reason from the ASPSP response.
reason: String,
},
/// Currency mismatch between request, account, and (optionally) consent.
#[error("currency mismatch: {0}")]
CurrencyMismatch(String),
/// Arithmetic overflow on a Money sum.
#[error("arithmetic overflow")]
Overflow,
/// The standard binding does not support the requested operation
/// (e.g. VRP under STET, which has no VRP profile in v1.7).
#[error("operation not supported by binding: {0}")]
UnsupportedByBinding(&'static str),
/// Anything bubbled up from `op-core`.
#[error("op-core error: {0}")]
Core(#[from] op_core::Error),
}