Skip to main content

replay_core/
error.rs

1//! Error types. Fail loudly, fail specifically — every variant carries the
2//! context a user needs to understand and act on the failure.
3
4use std::borrow::Cow;
5
6#[derive(Debug, thiserror::Error)]
7pub enum ReplayError {
8    #[error("invalid signature: {0}")]
9    InvalidSignature(String),
10
11    #[error("transaction not found on Helius")]
12    TxNotFound,
13
14    #[error("rpc error: {0}")]
15    Rpc(String),
16
17    #[error("http transport error: {0}")]
18    Http(#[from] reqwest::Error),
19
20    #[error("serde error: {0}")]
21    Serde(#[from] serde_json::Error),
22
23    #[error("state reconstruction failed at step `{step}`: {detail}")]
24    StateReconstruction { step: Cow<'static, str>, detail: String },
25
26    #[error("slot {slot} may be pruned; try a more recent transaction (Helius retains ~90 days)")]
27    SlotPruned { slot: u64 },
28
29    #[error("program {program_id} has no known bytecode at slot {slot}")]
30    MissingProgramBytecode { program_id: String, slot: u64 },
31
32    #[error("address lookup table {lut} resolution failed: {detail}")]
33    LutResolution { lut: String, detail: String },
34
35    #[error("execution error: {0}")]
36    Execution(String),
37
38    #[error("IDL parse error for program {program_id}: {detail}")]
39    Idl { program_id: String, detail: String },
40
41    #[error("account decoder error: {0}")]
42    Decoder(String),
43
44    #[error("mutation path `{path}` not valid for account type `{type_name}`")]
45    InvalidMutationPath { path: String, type_name: String },
46
47    #[error("session expired or not found: {0}")]
48    SessionNotFound(String),
49
50    #[error("io error: {0}")]
51    Io(#[from] std::io::Error),
52}
53
54impl ReplayError {
55    /// Short, stable error code suitable for a JSON payload.
56    /// Kept out of Display because the error message is already rich.
57    pub fn code(&self) -> &'static str {
58        match self {
59            Self::InvalidSignature(_) => "INVALID_SIGNATURE",
60            Self::TxNotFound => "TX_NOT_FOUND",
61            Self::Rpc(_) | Self::Http(_) => "RPC_ERROR",
62            Self::Serde(_) => "SERDE_ERROR",
63            Self::StateReconstruction { .. } => "STATE_RECONSTRUCTION_FAILED",
64            Self::SlotPruned { .. } => "SLOT_PRUNED",
65            Self::MissingProgramBytecode { .. } => "MISSING_PROGRAM_BYTECODE",
66            Self::LutResolution { .. } => "LUT_RESOLUTION_FAILED",
67            Self::Execution(_) => "EXECUTION_ERROR",
68            Self::Idl { .. } => "IDL_ERROR",
69            Self::Decoder(_) => "DECODER_ERROR",
70            Self::InvalidMutationPath { .. } => "INVALID_MUTATION_PATH",
71            Self::SessionNotFound(_) => "SESSION_NOT_FOUND",
72            Self::Io(_) => "IO_ERROR",
73        }
74    }
75}