Skip to main content

pgwire_replication/
error.rs

1//! Error types for pgwire-replication.
2//!
3//! All errors in this crate are represented by [`PgWireError`], which covers:
4//! - I/O errors (network, file system)
5//! - Protocol errors (malformed messages, unexpected responses)
6//! - Server errors (PostgreSQL error responses)
7//! - Authentication errors (wrong password, unsupported method)
8//! - TLS errors (handshake failure, certificate issues)
9//! - Task errors (worker panics, unexpected termination)
10//! - Message-size errors (a frame larger than the configured limit)
11
12use std::sync::Arc;
13use thiserror::Error;
14
15/// Error type for all pgwire-replication operations.
16///
17/// This enum is `#[non_exhaustive]`: match on it with a `_` arm so that new
18/// variants can be added without a breaking release.
19#[derive(Debug, Error, Clone)]
20#[non_exhaustive]
21pub enum PgWireError {
22    /// I/O error (network, file system).
23    ///
24    /// Wraps `std::io::Error` in an `Arc` to preserve `ErrorKind` while
25    /// keeping `PgWireError` `Clone`. Use `.kind()` via `Arc`'s `Deref`.
26    #[error("io error: {0}")]
27    Io(Arc<std::io::Error>),
28
29    /// Protocol error - malformed message or unexpected response.
30    #[error("protocol error: {0}")]
31    Protocol(String),
32
33    /// Server error - PostgreSQL returned an error response.
34    ///
35    /// The message typically includes SQLSTATE code.
36    #[error("server error: {0}")]
37    Server(String),
38
39    /// Authentication error - wrong credentials or unsupported method.
40    #[error("authentication error: {0}")]
41    Auth(String),
42
43    /// TLS error - handshake failure, certificate validation, etc.
44    #[error("tls error: {0}")]
45    Tls(String),
46
47    /// Task error - worker panicked or terminated unexpectedly.
48    #[error("task error: {0}")]
49    Task(String),
50
51    /// Internal error - bug in the library.
52    #[error("internal error: {0}")]
53    Internal(String),
54
55    /// A backend message announced a payload larger than the configured
56    /// limit, so it was refused before any of it was buffered.
57    ///
58    /// Distinct from [`Protocol`](Self::Protocol) so a caller can tell a
59    /// legitimate frame over its own
60    /// [`max_message_size`](crate::config::ReplicationConfig::max_message_size)
61    /// apart from malformed framing, and report which bound was exceeded
62    /// without parsing the message text. Non-transient: the refused payload
63    /// is never consumed, so the connection cannot be resumed.
64    #[error("backend message too large: {payload_bytes} bytes (max {limit_bytes})")]
65    MessageTooLarge {
66        /// Payload size the server announced, in bytes.
67        payload_bytes: usize,
68        /// Limit that refused it, in bytes.
69        limit_bytes: usize,
70    },
71}
72
73impl PgWireError {
74    /// Returns `true` if this is an I/O error.
75    #[inline]
76    pub fn is_io(&self) -> bool {
77        matches!(self, PgWireError::Io(_))
78    }
79
80    /// Returns `true` if this is a server error.
81    #[inline]
82    pub fn is_server(&self) -> bool {
83        matches!(self, PgWireError::Server(_))
84    }
85
86    /// Returns `true` if this is an authentication error.
87    #[inline]
88    pub fn is_auth(&self) -> bool {
89        matches!(self, PgWireError::Auth(_))
90    }
91
92    /// Returns `true` if this is a TLS error.
93    #[inline]
94    pub fn is_tls(&self) -> bool {
95        matches!(self, PgWireError::Tls(_))
96    }
97
98    /// Returns `true` if this is a message-size error.
99    #[inline]
100    pub fn is_message_too_large(&self) -> bool {
101        matches!(self, PgWireError::MessageTooLarge { .. })
102    }
103
104    /// Returns `true` if this error is likely transient and retryable.
105    ///
106    /// Transient errors include I/O errors and task errors. Non-transient
107    /// errors (auth, server, protocol) typically require configuration changes.
108    pub fn is_transient(&self) -> bool {
109        matches!(self, PgWireError::Io(_) | PgWireError::Task(_))
110    }
111}
112
113impl From<std::io::Error> for PgWireError {
114    fn from(err: std::io::Error) -> Self {
115        PgWireError::Io(Arc::new(err))
116    }
117}
118
119/// Result type alias for pgwire-replication operations.
120pub type Result<T> = std::result::Result<T, PgWireError>;