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}