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>;