liquid_cache_server/
errors.rs

1//! Error handling utilities for LiquidCache server.
2//!
3//! This module provides enhanced error handling with stack traces to help
4//! developers and users identify the exact location where errors occur.
5
6use anyhow::{Context, Result as AnyhowResult};
7use tonic::Status;
8
9/// Result type alias for LiquidCache operations
10pub type LiquidCacheResult<T> = AnyhowResult<T>;
11
12/// Extension trait to add context to Results for better error reporting
13pub trait LiquidCacheErrorExt<T> {
14    /// Add context to an error for better error reporting
15    fn with_liquid_context(self, message: impl Into<String>) -> LiquidCacheResult<T>;
16}
17
18impl<T, E> LiquidCacheErrorExt<T> for Result<T, E>
19where
20    E: std::error::Error + Send + Sync + 'static,
21{
22    fn with_liquid_context(self, message: impl Into<String>) -> LiquidCacheResult<T> {
23        self.map_err(anyhow::Error::from).context(message.into())
24    }
25}
26
27/// Convert anyhow::Error to tonic Status with detailed error information including stack trace
28pub fn anyhow_to_status(err: anyhow::Error) -> Status {
29    // Format the error with full error chain and backtrace for debugging
30    let error_with_context = format!("{err:?}");
31
32    // Determine the appropriate gRPC status code based on error type
33    if let Some(datafusion_err) = err.downcast_ref::<datafusion::error::DataFusionError>() {
34        match datafusion_err {
35            datafusion::error::DataFusionError::Plan(_) => {
36                Status::invalid_argument(error_with_context)
37            }
38            datafusion::error::DataFusionError::SchemaError(_, _) => {
39                Status::invalid_argument(error_with_context)
40            }
41            _ => Status::internal(error_with_context),
42        }
43    } else if err.downcast_ref::<url::ParseError>().is_some()
44        || err.downcast_ref::<uuid::Error>().is_some()
45    {
46        Status::invalid_argument(error_with_context)
47    } else if err.downcast_ref::<object_store::Error>().is_some() {
48        Status::internal(error_with_context)
49    } else {
50        // Default to internal error for unknown error types
51        Status::internal(error_with_context)
52    }
53}
54
55/// Legacy compatibility: convert DataFusionError to Status with stack trace
56pub fn df_error_to_status_with_trace(err: datafusion::error::DataFusionError) -> Status {
57    anyhow_to_status(err.into())
58}