scouter_drift/
error.rs

1use futures::io;
2use potato_head::error::WorkflowError;
3use pyo3::exceptions::PyRuntimeError;
4use pyo3::PyErr;
5use scouter_dispatch::error::DispatchError;
6#[cfg(feature = "sql")]
7use scouter_sql::sql::error::SqlError;
8use thiserror::Error;
9
10#[derive(Error, Debug)]
11pub enum DriftError {
12    #[error("Failed to compute mean")]
13    ComputeMeanError,
14
15    #[error("At least 10 values needed to compute deciles")]
16    NotEnoughDecileValuesError,
17
18    #[error("Failed to convert deciles to array")]
19    ConvertDecileToArray,
20
21    #[error("Failed to compute deciles")]
22    ComputeDecilesError,
23
24    #[error("{0}")]
25    RunTimeError(String),
26
27    #[error("Feature and array length mismatch")]
28    FeatureLengthError,
29
30    #[error("Feature does not exist")]
31    FeatureNotExistError,
32
33    #[error(transparent)]
34    ShapeError(#[from] ndarray::ShapeError),
35
36    #[cfg(feature = "sql")]
37    #[error(transparent)]
38    SqlError(#[from] SqlError),
39
40    #[error(transparent)]
41    UtilError(#[from] potato_head::UtilError),
42
43    #[error("SPC rule length is not 8")]
44    SpcRuleLengthError,
45
46    #[error(transparent)]
47    ParseIntError(#[from] std::num::ParseIntError),
48
49    #[error(transparent)]
50    DispatchError(#[from] DispatchError),
51
52    #[error("Failed to process alerts")]
53    ProcessAlertError,
54
55    #[error("Invalid configuration provided for drifter. Please check that the configuration type matches the drifter type")]
56    InvalidConfigError,
57
58    #[error("Not implemented")]
59    NotImplemented,
60
61    #[error("Data type not supported: {0}")]
62    UnsupportedDataTypeError(String),
63
64    #[error("Failed to downcast Python object: {0}")]
65    DowncastError(String),
66
67    #[error(transparent)]
68    ProfileError(#[from] scouter_types::error::ProfileError),
69
70    #[error("Invalid drift type")]
71    InvalidDriftType,
72
73    #[error("Error processing alert: {0}")]
74    AlertProcessingError(String),
75
76    #[error("Feature to monitor: {0}, not present in data")]
77    FeatureToMonitorMissingError(String),
78
79    #[error("Categorical feature specified in drift config: {0}, not present in data")]
80    CategoricalFeatureMissingError(String),
81
82    #[error("Empty Array Detected: {0}")]
83    EmptyArrayError(String),
84
85    #[error("Failed to compute binning edges: {0}")]
86    BinningError(String),
87
88    #[error("Failed to deserialize: {0}")]
89    SerdeJsonError(#[from] serde_json::Error),
90
91    #[error("Context is not a valid JSON object. Should be a Map<String, Value>")]
92    InvalidContextFormat,
93
94    #[error(transparent)]
95    WorkflowError(#[from] WorkflowError),
96
97    #[error("Incorrect method called: {0}")]
98    WrongMethodError(String),
99
100    #[error("Invalid content type. Expected a json string or value")]
101    InvalidContentTypeError,
102
103    #[error("Failed to setup tokio runtime for computing LLM drift: {0}")]
104    SetupTokioRuntimeError(#[source] io::Error),
105
106    #[error("Failed to process LLM drift record: {0}")]
107    LLMEvaluatorError(String),
108}
109
110impl<'a> From<pyo3::DowncastError<'a, 'a>> for DriftError {
111    fn from(err: pyo3::DowncastError) -> Self {
112        DriftError::DowncastError(err.to_string())
113    }
114}
115
116impl From<DriftError> for PyErr {
117    fn from(err: DriftError) -> PyErr {
118        let msg = err.to_string();
119        PyRuntimeError::new_err(msg)
120    }
121}
122
123impl From<PyErr> for DriftError {
124    fn from(err: PyErr) -> DriftError {
125        DriftError::RunTimeError(err.to_string())
126    }
127}