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("Failed to deserialize: {0}")]
83    SerdeJsonError(#[from] serde_json::Error),
84
85    #[error("Context is not a valid JSON object. Should be a Map<String, Value>")]
86    InvalidContextFormat,
87
88    #[error(transparent)]
89    WorkflowError(#[from] WorkflowError),
90
91    #[error("Incorrect method called: {0}")]
92    WrongMethodError(String),
93
94    #[error("Invalid content type. Expected a json string or value")]
95    InvalidContentTypeError,
96
97    #[error("Failed to setup tokio runtime for computing LLM drift: {0}")]
98    SetupTokioRuntimeError(#[source] io::Error),
99
100    #[error("Failed to process LLM drift record: {0}")]
101    LLMEvaluatorError(String),
102}
103
104impl<'a> From<pyo3::DowncastError<'a, 'a>> for DriftError {
105    fn from(err: pyo3::DowncastError) -> Self {
106        DriftError::DowncastError(err.to_string())
107    }
108}
109
110impl From<DriftError> for PyErr {
111    fn from(err: DriftError) -> PyErr {
112        let msg = err.to_string();
113        PyRuntimeError::new_err(msg)
114    }
115}
116
117impl From<PyErr> for DriftError {
118    fn from(err: PyErr) -> DriftError {
119        DriftError::RunTimeError(err.to_string())
120    }
121}