1use std::any::Any;
18
19use api::v1::CreateTableExpr;
20use arrow_schema::ArrowError;
21use common_error::ext::BoxedError;
22use common_error::{define_into_tonic_status, from_err_code_msg_to_header};
23use common_macro::stack_trace_debug;
24use common_telemetry::common_error::ext::ErrorExt;
25use common_telemetry::common_error::status_code::StatusCode;
26use snafu::{Location, ResultExt, Snafu};
27use tonic::metadata::MetadataMap;
28
29use crate::FlowId;
30use crate::expr::EvalError;
31
32#[derive(Snafu)]
34#[snafu(visibility(pub))]
35#[stack_trace_debug]
36pub enum Error {
37 #[snafu(display(
38 "Failed to insert into flow: region_id={}, flow_ids={:?}",
39 region_id,
40 flow_ids
41 ))]
42 InsertIntoFlow {
43 region_id: u64,
44 flow_ids: Vec<u64>,
45 source: BoxedError,
46 #[snafu(implicit)]
47 location: Location,
48 },
49
50 #[snafu(display("Flow engine is still recovering"))]
51 FlowNotRecovered {
52 #[snafu(implicit)]
53 location: Location,
54 },
55
56 #[snafu(display("Error encountered while creating flow: {sql}"))]
57 CreateFlow {
58 sql: String,
59 source: BoxedError,
60 #[snafu(implicit)]
61 location: Location,
62 },
63
64 #[snafu(display("Error encountered while creating sink table for flow: {create:?}"))]
65 CreateSinkTable {
66 create: CreateTableExpr,
67 source: BoxedError,
68 #[snafu(implicit)]
69 location: Location,
70 },
71
72 #[snafu(display("Time error"))]
73 Time {
74 source: common_time::error::Error,
75 #[snafu(implicit)]
76 location: Location,
77 },
78
79 #[snafu(display("No available frontend found after timeout: {timeout:?}, context: {context}"))]
80 NoAvailableFrontend {
81 timeout: std::time::Duration,
82 context: String,
83 #[snafu(implicit)]
84 location: Location,
85 },
86
87 #[snafu(display("External error"))]
88 External {
89 source: BoxedError,
90 #[snafu(implicit)]
91 location: Location,
92 },
93
94 #[snafu(display("Internal error"))]
95 Internal {
96 reason: String,
97 #[snafu(implicit)]
98 location: Location,
99 },
100
101 #[snafu(display("Failed to eval stream"))]
103 Eval {
104 source: EvalError,
105 #[snafu(implicit)]
106 location: Location,
107 },
108
109 #[snafu(display("Table not found: {name}"))]
110 TableNotFound {
111 name: String,
112 #[snafu(implicit)]
113 location: Location,
114 },
115
116 #[snafu(display("Table not found: {msg}, meta error: {source}"))]
117 TableNotFoundMeta {
118 source: common_meta::error::Error,
119 msg: String,
120 #[snafu(implicit)]
121 location: Location,
122 },
123
124 #[snafu(display("Flow not found, id={id}"))]
125 FlowNotFound {
126 id: FlowId,
127 #[snafu(implicit)]
128 location: Location,
129 },
130
131 #[snafu(display("Failed to list flows in flownode={id:?}"))]
132 ListFlows {
133 id: Option<common_meta::FlownodeId>,
134 source: common_meta::error::Error,
135 #[snafu(implicit)]
136 location: Location,
137 },
138
139 #[snafu(display("Flow already exist, id={id}"))]
140 FlowAlreadyExist {
141 id: FlowId,
142 #[snafu(implicit)]
143 location: Location,
144 },
145
146 #[snafu(display("Failed to join task"))]
147 JoinTask {
148 #[snafu(source)]
149 error: tokio::task::JoinError,
150 #[snafu(implicit)]
151 location: Location,
152 },
153
154 #[snafu(display("Invalid query: {reason}"))]
155 InvalidQuery {
156 reason: String,
157 #[snafu(implicit)]
158 location: Location,
159 },
160
161 #[snafu(display("Not implement in flow: {reason}"))]
162 NotImplemented {
163 reason: String,
164 #[snafu(implicit)]
165 location: Location,
166 },
167
168 #[snafu(display("Flow plan error: {reason}"))]
169 Plan {
170 reason: String,
171 #[snafu(implicit)]
172 location: Location,
173 },
174
175 #[snafu(display("Unsupported: {reason}"))]
176 Unsupported {
177 reason: String,
178 #[snafu(implicit)]
179 location: Location,
180 },
181
182 #[snafu(display("Unsupported temporal filter: {reason}"))]
183 UnsupportedTemporalFilter {
184 reason: String,
185 #[snafu(implicit)]
186 location: Location,
187 },
188
189 #[snafu(display("Datatypes error: {source} with extra message: {extra}"))]
190 Datatypes {
191 source: datatypes::Error,
192 extra: String,
193 #[snafu(implicit)]
194 location: Location,
195 },
196
197 #[snafu(display("Arrow error: {raw:?} in context: {context}"))]
198 Arrow {
199 #[snafu(source)]
200 raw: ArrowError,
201 context: String,
202 #[snafu(implicit)]
203 location: Location,
204 },
205
206 #[snafu(display("Datafusion error: {raw:?} in context: {context}"))]
207 Datafusion {
208 #[snafu(source)]
209 raw: datafusion_common::DataFusionError,
210 context: String,
211 #[snafu(implicit)]
212 location: Location,
213 },
214
215 #[snafu(display("Unexpected: {reason}"))]
216 Unexpected {
217 reason: String,
218 #[snafu(implicit)]
219 location: Location,
220 },
221
222 #[snafu(display("Illegal check task state: {reason}"))]
223 IllegalCheckTaskState {
224 reason: String,
225 #[snafu(implicit)]
226 location: Location,
227 },
228
229 #[snafu(display(
230 "Failed to sync with check task for flow {} with allow_drop={}",
231 flow_id,
232 allow_drop
233 ))]
234 SyncCheckTask {
235 flow_id: FlowId,
236 allow_drop: bool,
237 #[snafu(implicit)]
238 location: Location,
239 },
240
241 #[snafu(display("Failed to start server"))]
242 StartServer {
243 #[snafu(implicit)]
244 location: Location,
245 source: servers::error::Error,
246 },
247
248 #[snafu(display("Failed to shutdown server"))]
249 ShutdownServer {
250 #[snafu(implicit)]
251 location: Location,
252 source: servers::error::Error,
253 },
254
255 #[snafu(display("Failed to initialize meta client"))]
256 MetaClientInit {
257 #[snafu(implicit)]
258 location: Location,
259 source: meta_client::error::Error,
260 },
261
262 #[snafu(display("Failed to parse address {}", addr))]
263 ParseAddr {
264 addr: String,
265 #[snafu(source)]
266 error: std::net::AddrParseError,
267 },
268
269 #[snafu(display("Failed to get cache from cache registry: {}", name))]
270 CacheRequired {
271 #[snafu(implicit)]
272 location: Location,
273 name: String,
274 },
275
276 #[snafu(display("Invalid request: {context}"))]
277 InvalidRequest {
278 context: String,
279 source: client::Error,
280 #[snafu(implicit)]
281 location: Location,
282 },
283
284 #[snafu(display("Failed to encode logical plan in substrait"))]
285 SubstraitEncodeLogicalPlan {
286 #[snafu(implicit)]
287 location: Location,
288 source: substrait::error::Error,
289 },
290
291 #[snafu(display("Failed to convert column schema to proto column def"))]
292 ConvertColumnSchema {
293 #[snafu(implicit)]
294 location: Location,
295 source: operator::error::Error,
296 },
297
298 #[snafu(display("Failed to create channel manager for gRPC client"))]
299 InvalidClientConfig {
300 #[snafu(implicit)]
301 location: Location,
302 source: common_grpc::error::Error,
303 },
304}
305
306pub fn to_status_with_last_err(err: impl ErrorExt) -> tonic::Status {
308 let msg = err.to_string();
309 let last_err_msg = common_error::ext::StackError::last(&err).to_string();
310 let code = err.status_code() as u32;
311 let header = from_err_code_msg_to_header(code, &last_err_msg);
312
313 tonic::Status::with_metadata(
314 tonic::Code::InvalidArgument,
315 msg,
316 MetadataMap::from_headers(header),
317 )
318}
319
320pub type Result<T> = std::result::Result<T, Error>;
322
323impl ErrorExt for Error {
324 fn status_code(&self) -> StatusCode {
325 match self {
326 Self::Eval { .. }
327 | Self::JoinTask { .. }
328 | Self::Datafusion { .. }
329 | Self::InsertIntoFlow { .. }
330 | Self::NoAvailableFrontend { .. }
331 | Self::FlowNotRecovered { .. } => StatusCode::Internal,
332 Self::FlowAlreadyExist { .. } => StatusCode::TableAlreadyExists,
333 Self::TableNotFound { .. }
334 | Self::TableNotFoundMeta { .. }
335 | Self::ListFlows { .. } => StatusCode::TableNotFound,
336 Self::FlowNotFound { .. } => StatusCode::FlowNotFound,
337 Self::Plan { .. } | Self::Datatypes { .. } => StatusCode::PlanQuery,
338 Self::CreateFlow { .. }
339 | Self::CreateSinkTable { .. }
340 | Self::Arrow { .. }
341 | Self::Time { .. } => StatusCode::EngineExecuteQuery,
342 Self::Unexpected { .. }
343 | Self::SyncCheckTask { .. }
344 | Self::IllegalCheckTaskState { .. } => StatusCode::Unexpected,
345 Self::NotImplemented { .. }
346 | Self::UnsupportedTemporalFilter { .. }
347 | Self::Unsupported { .. } => StatusCode::Unsupported,
348 Self::External { source, .. } => source.status_code(),
349 Self::Internal { .. } | Self::CacheRequired { .. } => StatusCode::Internal,
350 Self::StartServer { source, .. } | Self::ShutdownServer { source, .. } => {
351 source.status_code()
352 }
353 Self::MetaClientInit { source, .. } => source.status_code(),
354
355 Self::InvalidQuery { .. }
356 | Self::InvalidRequest { .. }
357 | Self::ParseAddr { .. }
358 | Self::InvalidClientConfig { .. } => StatusCode::InvalidArguments,
359
360 Error::SubstraitEncodeLogicalPlan { source, .. } => source.status_code(),
361
362 Error::ConvertColumnSchema { source, .. } => source.status_code(),
363 }
364 }
365
366 fn as_any(&self) -> &dyn Any {
367 self
368 }
369}
370
371define_into_tonic_status!(Error);
372
373impl From<EvalError> for Error {
374 fn from(e: EvalError) -> Self {
375 Err::<(), _>(e).context(EvalSnafu).unwrap_err()
376 }
377}