temporalio_client/
errors.rs1use http::uri::InvalidUri;
4use temporalio_common::{
5 data_converters::PayloadConversionError,
6 protos::temporal::api::{common::v1::Payload, failure::v1::Failure, query::v1::QueryRejected},
7};
8use tonic::Code;
9
10#[derive(thiserror::Error, Debug)]
12#[non_exhaustive]
13pub enum ClientConnectError {
14 #[error("Invalid URI: {0:?}")]
16 InvalidUri(#[from] InvalidUri),
17 #[error("Invalid headers: {0}")]
19 InvalidHeaders(#[from] InvalidHeaderError),
20 #[error("Server connection error: {0:?}")]
22 TonicTransportError(#[from] tonic::transport::Error),
23 #[error("`get_system_info` call error after connection: {0:?}")]
26 SystemInfoCallError(tonic::Status),
27}
28
29#[derive(thiserror::Error, Debug)]
31#[non_exhaustive]
32pub enum InvalidHeaderError {
33 #[error("Invalid binary header key '{key}': {source}")]
35 InvalidBinaryHeaderKey {
36 key: String,
38 source: tonic::metadata::errors::InvalidMetadataKey,
40 },
41 #[error("Invalid ASCII header key '{key}': {source}")]
43 InvalidAsciiHeaderKey {
44 key: String,
46 source: tonic::metadata::errors::InvalidMetadataKey,
48 },
49 #[error("Invalid ASCII header value for key '{key}': {source}")]
51 InvalidAsciiHeaderValue {
52 key: String,
54 value: String,
56 source: tonic::metadata::errors::InvalidMetadataValue,
58 },
59}
60
61#[derive(thiserror::Error, Debug)]
63#[non_exhaustive]
64pub enum WorkflowStartError {
65 #[error("Workflow already started with run ID: {run_id:?}")]
67 AlreadyStarted {
68 run_id: Option<String>,
70 #[source]
72 source: tonic::Status,
73 },
74 #[error("Failed to serialize workflow input: {0}")]
76 PayloadConversion(#[from] PayloadConversionError),
77 #[error("Server error: {0}")]
79 Rpc(#[from] tonic::Status),
80}
81
82#[derive(Debug, thiserror::Error)]
84#[non_exhaustive]
85pub enum WorkflowQueryError {
86 #[error("Workflow not found")]
88 NotFound(#[source] tonic::Status),
89
90 #[error("Query rejected: workflow status {:?}", .0.status)]
92 Rejected(QueryRejected),
93
94 #[error("Payload conversion error: {0}")]
96 PayloadConversion(#[from] PayloadConversionError),
97
98 #[error("Server error: {0}")]
100 Rpc(tonic::Status),
101
102 #[error(transparent)]
104 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
105}
106
107impl WorkflowQueryError {
108 pub(crate) fn from_status(status: tonic::Status) -> Self {
109 if status.code() == Code::NotFound {
110 Self::NotFound(status)
111 } else {
112 Self::Rpc(status)
113 }
114 }
115}
116
117#[derive(Debug, thiserror::Error)]
119#[non_exhaustive]
120pub enum WorkflowUpdateError {
121 #[error("Workflow not found")]
123 NotFound(#[source] tonic::Status),
124
125 #[error("Update failed: {0:?}")]
127 Failed(Box<Failure>),
128
129 #[error("Payload conversion error: {0}")]
131 PayloadConversion(#[from] PayloadConversionError),
132
133 #[error("Server error: {0}")]
135 Rpc(tonic::Status),
136
137 #[error(transparent)]
139 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
140}
141
142impl WorkflowUpdateError {
143 pub(crate) fn from_status(status: tonic::Status) -> Self {
144 if status.code() == Code::NotFound {
145 Self::NotFound(status)
146 } else {
147 Self::Rpc(status)
148 }
149 }
150}
151
152#[derive(Debug, thiserror::Error)]
154#[non_exhaustive]
155pub enum WorkflowGetResultError {
156 #[error("Workflow failed: {0:?}")]
158 Failed(Box<Failure>),
159
160 #[error("Workflow cancelled")]
162 Cancelled {
163 details: Vec<Payload>,
165 },
166
167 #[error("Workflow terminated")]
169 Terminated {
170 details: Vec<Payload>,
172 },
173
174 #[error("Workflow timed out")]
176 TimedOut,
177
178 #[error("Workflow continued as new")]
180 ContinuedAsNew,
181
182 #[error("Workflow not found")]
184 NotFound(#[source] tonic::Status),
185
186 #[error("Payload conversion error: {0}")]
188 PayloadConversion(#[from] PayloadConversionError),
189
190 #[error("Server error: {0}")]
192 Rpc(tonic::Status),
193
194 #[error(transparent)]
196 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
197}
198
199impl From<WorkflowInteractionError> for WorkflowGetResultError {
200 fn from(err: WorkflowInteractionError) -> Self {
201 match err {
202 WorkflowInteractionError::NotFound(s) => Self::NotFound(s),
203 WorkflowInteractionError::PayloadConversion(e) => Self::PayloadConversion(e),
204 WorkflowInteractionError::Rpc(s) => Self::Rpc(s),
205 WorkflowInteractionError::Other(e) => Self::Other(e),
206 }
207 }
208}
209
210impl WorkflowGetResultError {
211 pub fn is_workflow_outcome(&self) -> bool {
215 matches!(
216 self,
217 Self::Failed(_)
218 | Self::Cancelled { .. }
219 | Self::Terminated { .. }
220 | Self::TimedOut
221 | Self::ContinuedAsNew
222 )
223 }
224}
225
226#[derive(thiserror::Error, Debug)]
228#[non_exhaustive]
229pub enum ClientError {
230 #[error("Server error: {0}")]
232 Rpc(#[from] tonic::Status),
233}
234
235#[derive(Debug, thiserror::Error)]
238#[non_exhaustive]
239pub enum WorkflowInteractionError {
240 #[error("Workflow not found")]
242 NotFound(#[source] tonic::Status),
243
244 #[error("Payload conversion error: {0}")]
246 PayloadConversion(#[from] PayloadConversionError),
247
248 #[error("Server error: {0}")]
250 Rpc(tonic::Status),
251
252 #[error(transparent)]
254 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
255}
256
257impl WorkflowInteractionError {
258 pub(crate) fn from_status(status: tonic::Status) -> Self {
259 if status.code() == Code::NotFound {
260 Self::NotFound(status)
261 } else {
262 Self::Rpc(status)
263 }
264 }
265}
266
267#[derive(Debug, thiserror::Error)]
269#[non_exhaustive]
270pub enum AsyncActivityError {
271 #[error("Activity not found")]
273 NotFound(#[source] tonic::Status),
274 #[error("Server error: {0}")]
276 Rpc(#[from] tonic::Status),
277}
278
279impl AsyncActivityError {
280 pub(crate) fn from_status(status: tonic::Status) -> Self {
281 if status.code() == Code::NotFound {
282 Self::NotFound(status)
283 } else {
284 Self::Rpc(status)
285 }
286 }
287}
288
289#[derive(Debug, thiserror::Error)]
293#[non_exhaustive]
294pub enum ClientNewError {}