temporalio_client/
errors.rs1use crate::{WorkflowExecutionStatus, workflow_handle::WorkflowResultDetails};
4use http::uri::InvalidUri;
5use temporalio_common::{
6 data_converters::PayloadConversionError, error::IncomingError,
7 protos::temporal::api::failure::v1::Failure,
8};
9use tonic::Code;
10
11#[derive(thiserror::Error, Debug)]
13#[non_exhaustive]
14pub enum ClientConnectError {
15 #[error("Invalid URI: {0:?}")]
17 InvalidUri(#[from] InvalidUri),
18 #[error("Invalid headers: {0}")]
20 InvalidHeaders(#[from] InvalidHeaderError),
21 #[error("Server connection error: {0:?}")]
23 TonicTransportError(#[from] tonic::transport::Error),
24 #[error("`get_system_info` call error after connection: {0:?}")]
27 SystemInfoCallError(tonic::Status),
28 #[error("DNS resolution error for '{host}': {source}")]
30 DnsResolutionError {
31 host: String,
33 #[source]
35 source: std::io::Error,
36 },
37 #[error("Invalid client configuration: {0}")]
39 InvalidConfig(String),
40}
41
42#[derive(thiserror::Error, Debug)]
44#[non_exhaustive]
45pub enum InvalidHeaderError {
46 #[error("Invalid binary header key '{key}': {source}")]
48 InvalidBinaryHeaderKey {
49 key: String,
51 source: tonic::metadata::errors::InvalidMetadataKey,
53 },
54 #[error("Invalid ASCII header key '{key}': {source}")]
56 InvalidAsciiHeaderKey {
57 key: String,
59 source: tonic::metadata::errors::InvalidMetadataKey,
61 },
62 #[error("Invalid ASCII header value for key '{key}': {source}")]
64 InvalidAsciiHeaderValue {
65 key: String,
67 value: String,
69 source: tonic::metadata::errors::InvalidMetadataValue,
71 },
72}
73
74#[derive(thiserror::Error, Debug)]
76#[non_exhaustive]
77pub enum WorkflowStartError {
78 #[error("Workflow already started with run ID: {run_id:?}")]
80 AlreadyStarted {
81 run_id: Option<String>,
83 #[source]
85 source: tonic::Status,
86 },
87 #[error("Failed to serialize workflow input: {0}")]
89 PayloadConversion(#[from] PayloadConversionError),
90 #[error("Server error: {0}")]
92 Rpc(#[from] tonic::Status),
93}
94
95#[derive(Debug, thiserror::Error)]
97#[non_exhaustive]
98pub enum WorkflowQueryError {
99 #[error("Workflow not found")]
101 NotFound(#[source] tonic::Status),
102
103 #[error("Query rejected: workflow status {status:?}")]
105 Rejected {
106 status: Option<WorkflowExecutionStatus>,
108 },
109
110 #[error("Payload conversion error: {0}")]
112 PayloadConversion(#[from] PayloadConversionError),
113
114 #[error("Server error: {0}")]
116 Rpc(tonic::Status),
117
118 #[error(transparent)]
120 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
121}
122
123impl WorkflowQueryError {
124 pub(crate) fn from_status(status: tonic::Status) -> Self {
125 if status.code() == Code::NotFound {
126 Self::NotFound(status)
127 } else {
128 Self::Rpc(status)
129 }
130 }
131}
132
133#[derive(Debug, thiserror::Error)]
135#[non_exhaustive]
136pub enum WorkflowUpdateError {
137 #[error("Workflow not found")]
139 NotFound(#[source] tonic::Status),
140
141 #[error("Update failed: {0:?}")]
143 Failed(Box<Failure>),
144
145 #[error("Payload conversion error: {0}")]
147 PayloadConversion(#[from] PayloadConversionError),
148
149 #[error("Server error: {0}")]
151 Rpc(tonic::Status),
152
153 #[error(transparent)]
155 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
156}
157
158impl WorkflowUpdateError {
159 pub(crate) fn from_status(status: tonic::Status) -> Self {
160 if status.code() == Code::NotFound {
161 Self::NotFound(status)
162 } else {
163 Self::Rpc(status)
164 }
165 }
166}
167
168#[derive(Debug, thiserror::Error)]
170#[non_exhaustive]
171pub enum WorkflowGetResultError {
172 #[error("Workflow failed: {0}")]
174 Failed(#[source] Box<IncomingError>),
175
176 #[error("Workflow cancelled")]
178 Cancelled {
179 details: WorkflowResultDetails,
181 },
182
183 #[error("Workflow terminated")]
185 Terminated {
186 details: WorkflowResultDetails,
188 },
189
190 #[error("Workflow timed out")]
192 TimedOut,
193
194 #[error("Workflow continued as new")]
196 ContinuedAsNew,
197
198 #[error("Workflow not found")]
200 NotFound(#[source] tonic::Status),
201
202 #[error("Payload conversion error: {0}")]
204 PayloadConversion(#[from] PayloadConversionError),
205
206 #[error("Server error: {0}")]
208 Rpc(tonic::Status),
209
210 #[error(transparent)]
212 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
213}
214
215impl From<WorkflowInteractionError> for WorkflowGetResultError {
216 fn from(err: WorkflowInteractionError) -> Self {
217 match err {
218 WorkflowInteractionError::NotFound(s) => Self::NotFound(s),
219 WorkflowInteractionError::PayloadConversion(e) => Self::PayloadConversion(e),
220 WorkflowInteractionError::Rpc(s) => Self::Rpc(s),
221 WorkflowInteractionError::Other(e) => Self::Other(e),
222 }
223 }
224}
225
226impl WorkflowGetResultError {
227 pub fn is_workflow_outcome(&self) -> bool {
231 matches!(
232 self,
233 Self::Failed(_)
234 | Self::Cancelled { .. }
235 | Self::Terminated { .. }
236 | Self::TimedOut
237 | Self::ContinuedAsNew
238 )
239 }
240}
241
242#[derive(thiserror::Error, Debug)]
244#[non_exhaustive]
245pub enum ClientError {
246 #[error("Payload conversion error: {0}")]
248 PayloadConversion(#[from] PayloadConversionError),
249 #[error("Server error: {0}")]
251 Rpc(#[from] tonic::Status),
252}
253
254#[derive(Debug, thiserror::Error)]
257#[non_exhaustive]
258pub enum WorkflowInteractionError {
259 #[error("Workflow not found")]
261 NotFound(#[source] tonic::Status),
262
263 #[error("Payload conversion error: {0}")]
265 PayloadConversion(#[from] PayloadConversionError),
266
267 #[error("Server error: {0}")]
269 Rpc(tonic::Status),
270
271 #[error(transparent)]
273 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
274}
275
276impl WorkflowInteractionError {
277 pub(crate) fn from_status(status: tonic::Status) -> Self {
278 if status.code() == Code::NotFound {
279 Self::NotFound(status)
280 } else {
281 Self::Rpc(status)
282 }
283 }
284}
285
286#[derive(Debug, thiserror::Error)]
288#[non_exhaustive]
289pub enum AsyncActivityError {
290 #[error("Activity not found")]
292 NotFound(#[source] tonic::Status),
293 #[error("Payload conversion error: {0}")]
295 PayloadConversion(#[from] PayloadConversionError),
296 #[error("Server error: {0}")]
298 Rpc(#[from] tonic::Status),
299}
300
301impl AsyncActivityError {
302 pub(crate) fn from_status(status: tonic::Status) -> Self {
303 if status.code() == Code::NotFound {
304 Self::NotFound(status)
305 } else {
306 Self::Rpc(status)
307 }
308 }
309}
310
311#[derive(Debug, thiserror::Error)]
315#[non_exhaustive]
316pub enum ClientNewError {}