Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Error Handling

Meridian uses typed, explicit error handling throughout. No panics, no silent failures.

Error Types

CodecError (HTTP parsing)

#![allow(unused)]
fn main() {
pub enum CodecError {
    Io(std::io::Error),              // I/O layer failure
    Parse(String),                   // Malformed HTTP
    HeadersTooLarge,                 // >64KB headers
    InvalidHeader(String),           // Invalid header name/value
    RequestSmuggling,                // Both CL and TE present
    InvalidContentLength(String),    // Non-numeric or padded CL
    UnsupportedVersion,              // Not HTTP/1.0 or 1.1
    ConnectionClosed,                // Peer closed mid-parse
    ChunkedEncoding(String),         // Invalid chunked framing
    BodyTooLarge(usize),             // Body exceeds limit
}
}

FilterError (filter chain)

#![allow(unused)]
fn main() {
pub enum FilterError {
    Internal { filter: &'static str, source: Box<dyn Error> },
    Abort { filter: &'static str, reason: String },
    Timeout { filter: &'static str, elapsed: Duration },
}
}

TlsError (TLS configuration)

#![allow(unused)]
fn main() {
pub enum TlsError {
    Io { path: String, source: std::io::Error },
    NoCertificates(String),
    NoPrivateKey(String),
    Config(String),
}
}

MeridianError (top-level)

#![allow(unused)]
fn main() {
pub enum MeridianError {
    Io(std::io::Error),
    Config(String),
    FilterRejection { reason: String, status: u16 },
    UpstreamUnavailable(String),
    CircuitBreakerOpen { cluster: String },
    RateLimited,
    Timeout { elapsed_ms: u64 },
    Protocol(String),
    Parse(String),
}
}

Error-to-HTTP Mapping

Errors are mapped to generic HTTP status codes. Internal details are never sent to clients:

Internal ErrorClient SeesWhy Generic
CodecError::Parse400 Bad RequestDon’t reveal parser internals
No route match404 Not FoundSafe to expose
Cluster not found502 Bad GatewayDon’t reveal cluster names
CB open503 Service UnavailableDon’t reveal CB state
No healthy endpoints502 Bad GatewayDon’t reveal endpoint topology
Upstream connect fail502 Bad GatewayDon’t reveal upstream addresses
Upstream timeout504 Gateway TimeoutDon’t reveal timeout config
Filter error500 Internal Server ErrorDon’t reveal filter internals

All internal details are logged via tracing for operator debugging.

Conventions

  • Core library: every public function returns Result<T, ModuleError>
  • Proxy crate: uses anyhow::Result for application-level errors
  • No .unwrap() in core library code (enforced by pre-commit hook)
  • One error enum per module with thiserror #[derive(Error)]