d_engine/errors.rs
1use std::net::AddrParseError;
2
3use config::ConfigError;
4use thiserror::Error;
5use tokio::task::JoinError;
6
7use crate::proto::ClientRequestError;
8
9#[doc(hidden)]
10pub type Result<T> = std::result::Result<T, Error>;
11
12#[doc(hidden)]
13#[macro_export]
14macro_rules! define_error_mapping {
15 ($proto:ident, $app:ident; $($app_pattern:path => $proto_variant:path),+) => {
16 impl From<$app> for $proto {
17 fn from(e: $app) -> Self {
18 match e {
19 $(
20 $app_pattern => $proto_variant,
21 )+
22 _ => Self::Unknown,
23 }
24 }
25 }
26
27 impl From<$proto> for $app {
28 fn from(e: $proto) -> Self {
29 match e {
30 $(
31 $proto_variant => $app_pattern,
32 )+
33 _ => Self::ServerError,
34 }
35 }
36 }
37 };
38}
39
40/// Custom errors definition
41#[derive(Debug, Error)]
42pub enum Error {
43 /// General file IO error
44 #[error(transparent)]
45 IoError(#[from] std::io::Error),
46
47 /// Sled DB related error
48 #[error(transparent)]
49 SledError(#[from] sled::Error),
50
51 /// RPC framework tonic related error
52 #[error(transparent)]
53 TonicError(#[from] tonic::transport::Error),
54
55 /// General server error
56 #[error("General server error: {0}")]
57 GeneralServerError(String),
58
59 /// General server error without message
60 #[error("Server error")]
61 ServerError,
62
63 /// Bincode related error
64 #[error(transparent)]
65 BincodeError(#[from] bincode::Error),
66
67 /// Node start failed error
68 #[error("Node failed to start error")]
69 NodeFailedToStartError,
70
71 /// RPC connection error
72 #[error("Socket connect failed error")]
73 ConnectError,
74
75 /// Async task retry timeout error
76 #[error("Retry Timeout error")]
77 RetryTimeoutError,
78
79 /// State machine related error
80 #[error("State Machine error: {0}")]
81 StateMachinneError(String),
82
83 /// The request was sent to a follower or non-leader node; the client should retry with the
84 /// leader.
85 #[error("Dispatch client request leader error")]
86 NodeIsNotLeaderError,
87
88 /// The cluster has no known membership configuration; it may be unavailable or uninitialized.
89 #[error("Cluster is unavailable")]
90 ClusterMembershipNotFound,
91
92 /// Returned when the cluster has no elected leader or the leader is unknown.
93 /// This typically occurs during elections or network partitions.
94 #[error("No leader found")]
95 NoLeaderFound,
96
97 /// Returned when client `get_multi` is called without any keys.
98 #[error("No keys provided")]
99 EmptyKeys,
100
101 /// The response from the client response is invalid or missing expected data.
102 #[error("Invalid response")]
103 InvalidResponse,
104
105 /// Returned when the server response type does not match the expected variant for the
106 /// operation. Typically indicates a protocol mismatch or internal bug.
107 #[error("Invalid response type")]
108 InvalidResponseType,
109
110 /// Indicates failure to fetch or apply the latest cluster membership from the leader.
111 /// Additional context is included in the error message.
112 #[error("Failed to update cluster membership from leader, {0}")]
113 ClusterMembershipUpdateFailed(String),
114
115 /// Indicates that the Raft metadata for the given node ID was not found.
116 /// This usually occurs when the client or leader lacks an up-to-date cluster view,
117 /// or the node has not been properly registered in cluster membership.
118 ///
119 /// The `u32` parameter represents the node ID being queried.
120 #[error("Raft Metadata not found: {0}")]
121 ClusterMetadataNodeMetaNotFound(u32),
122
123 /// The follower could not confirm commitment of the log entry.
124 /// This may happen if the follower's log is not sufficiently up-to-date or quorum was not
125 /// reached.
126 #[error("AppendEntriesCommitNotConfirmed")]
127 AppendEntriesCommitNotConfirmed,
128
129 /// The current node rejected the AppendEntries request because it is not the leader.
130 /// Clients should redirect requests to the current cluster leader.
131 #[error("NotLeader")]
132 AppendEntriesNotLeader,
133
134 /// The target peer specified in the AppendEntries request was not found in the current cluster
135 /// view. This can occur if the membership view is outdated or the peer was removed.
136 #[error("No peer found")]
137 AppendEntriesNoPeerFound,
138
139 // The target peer failed to respond to the AppendEntries request within the expected timeout period.
140 /// Typically caused by network partitions, slow nodes, or overloaded peers.
141 #[error("ServerTimeoutResponding")]
142 AppendEntriesServerTimeoutResponding,
143
144 /// The node failed to win the election.
145 /// This could happen due to split vote, quorum not reached, or other election logic failure.
146 /// The error message may contain additional context such as vote count or term mismatch.
147 #[error("ElectionFailed: {0}")]
148 ElectionFailed(String),
149
150 /// Error occurred during a Raft state transition (e.g., follower → candidate, candidate →
151 /// leader). Propagates the underlying StateTransitionError.
152 #[error(transparent)]
153 StateTransitionError(#[from] StateTransitionError),
154
155 /// A message was received with a higher term than the local node's current term.
156 /// The node should step down and update its term accordingly.
157 #[error("Higher term found error: higher term = {0}")]
158 HigherTermFoundError(u64),
159
160 /// Receive Exist Signals
161 #[error("Exit")]
162 Exit,
163
164 /// Indicated RPC service stops serving
165 #[error("RPC server dies")]
166 RPCServerDies,
167
168 /// Indicate node is not ready to server request
169 #[error("Node is not ready error")]
170 ServerIsNotReadyError,
171
172 /// Receive status error from RPC service
173 #[error("Node status error: {0}")]
174 RPCServerStatusError(String),
175
176 /// The error is returned when the provided URI is invalid.
177 /// The error message will include the invalid URI for context.
178 #[error("invalid uri {0}")]
179 InvalidURI(String),
180
181 /// Indicates a failure to send a read request.
182 #[error("Failed to send read request error")]
183 FailedToSendReadRequestError,
184
185 /// Indicates a failure to send a write request.
186 #[error("Failed to send write request error")]
187 FailedToSendWriteRequestError,
188
189 /// A task retry failed, often due to reaching the maximum retry limit or encountering
190 /// persistent errors.
191 #[error("Task retry failed: {0}")]
192 RetryTaskFailed(String),
193
194 /// Address parsing error when invalid network address is encountered.
195 #[error(transparent)]
196 AddrParseError(#[from] AddrParseError),
197
198 /// Failed to set up a peer connection, possibly due to network or configuration issues.
199 /// The error message may contain more details about the failure.
200 #[error("Set peer connection failed: {0}")]
201 FailedSetPeerConnection(String),
202
203 /// General error indicating a configuration issue.
204 /// The error message will provide details about the specific configuration problem.
205 #[error(transparent)]
206 ConfigError(#[from] ConfigError),
207
208 /// Error encountered when sending a Tonic status via tokio.
209 /// The error message will include details about the status failure.
210 #[error("tokio send Tonic Status error: {0}")]
211 TokioSendStatusError(String),
212
213 //===== Role responbilitiies errors ====
214 /// The operation failed because the current node is not a leader.
215 #[error("Not Leader")]
216 NotLeader,
217
218 /// The operation failed because the node is a learner and cannot perform this action.
219 #[error("Learner can not handle")]
220 LearnerCanNot,
221
222 /// A generic error indicating an illegal state or operation.
223 #[error("Illegal")]
224 Illegal,
225
226 /// The error indicates that a state transition has failed.
227 #[error("Transition failed")]
228 TransitionFailed,
229
230 /// Error encountered when a tokio task join fails.
231 #[error(transparent)]
232 JoinError(#[from] JoinError),
233
234 //===== Client errors =====
235 //
236 /// General client request error
237 #[error("Client error: {0}")]
238 GeneralClientError(String),
239
240 //===== Config errors =====
241 //
242 /// Configuration is invalid. The error message will contain details about what is wrong with
243 /// the config.
244 #[error("Invalid config: {0}")]
245 InvalidConfig(String),
246}
247
248#[doc(hidden)]
249define_error_mapping!(
250 ClientRequestError, Error;
251 Error::AppendEntriesCommitNotConfirmed => ClientRequestError::CommitNotConfirmed,
252 Error::AppendEntriesNotLeader => ClientRequestError::NotLeader,
253 Error::AppendEntriesServerTimeoutResponding => ClientRequestError::ServerTimeout
254);
255
256#[derive(Debug, Error)]
257#[doc(hidden)]
258pub enum StateTransitionError {
259 #[error("Not enough votes to transition to leader.")]
260 NotEnoughVotes,
261
262 #[error("Invalid state transition.")]
263 InvalidTransition,
264
265 #[error("Lock error.")]
266 LockError,
267}