scouter_evaluate/
error.rs1use pyo3::exceptions::PyRuntimeError;
2use pyo3::pyclass::PyClassGuardError;
3use pyo3::PyErr;
4use pythonize::PythonizeError;
5use thiserror::Error;
6use tracing::error;
7#[derive(Error, Debug)]
8pub enum EvaluationError {
9 #[error("Invalid response type. Expected Score")]
10 InvalidResponseError,
11
12 #[error(transparent)]
13 WorkflowError(#[from] potato_head::WorkflowError),
14
15 #[error("{0}")]
16 DowncastError(String),
17
18 #[error(transparent)]
19 JoinError(#[from] tokio::task::JoinError),
20
21 #[error(transparent)]
22 RegexError(#[from] regex::Error),
23
24 #[error("Missing key: {0}")]
25 MissingKeyError(String),
26
27 #[error("Invalid context type. Context must be a PyDict or a Pydantic BaseModel")]
28 MustBeDictOrBaseModel,
29
30 #[error(transparent)]
31 IoError(#[from] std::io::Error),
32
33 #[error(transparent)]
34 TypeError(#[from] scouter_types::error::TypeError),
35
36 #[error("Invalid embedder type. Expected an instance of Embedder")]
37 InvalidEmbedderType,
38
39 #[error("No results found in evaluation results")]
40 NoResultsFound,
41
42 #[error(transparent)]
43 ShapeError(#[from] ndarray::ShapeError),
44
45 #[error(transparent)]
46 DataProfileError(#[from] scouter_profile::error::DataProfileError),
47
48 #[error(transparent)]
49 SerdeError(#[from] serde_json::Error),
50
51 #[error("Field '{0}' not found")]
52 FieldNotFound(String),
53
54 #[error("Index {0} not found")]
55 IndexNotFound(usize),
56
57 #[error("Invalid array index: {0}")]
58 InvalidArrayIndex(String),
59
60 #[error("Empty context path provided")]
61 EmptyFieldPath,
62
63 #[error("{0}")]
64 PyError(String),
65
66 #[error("Cannot compare non-numeric values")]
67 CannotCompareNonNumericValues,
68
69 #[error("Contains operation requires string or list")]
70 InvalidContainsOperation,
71
72 #[error("StartsWith operation requires strings")]
73 InvalidStartsWithOperation,
74
75 #[error("EndsWith operation requires strings")]
76 InvalidEndsWithOperation,
77
78 #[error("Regex match requires strings")]
79 InvalidRegexOperation,
80
81 #[error("Invalid number format")]
82 InvalidNumberFormat,
83
84 #[error("Cannot convert object to AssertionValue")]
85 CannotConvertObjectToAssertionValue,
86
87 #[error("Cannot get length of object")]
88 CannotGetLengthOfObject,
89
90 #[error("Expected value for length must be an integer")]
91 ExpectedLengthMustBeInteger,
92
93 #[error("Invalid assertion value type")]
94 InvalidAssertionValueType,
95
96 #[error("Invalid task type for evaluation")]
97 InvalidTaskType,
98
99 #[error("Cannot get length: {0}")]
100 CannotGetLength(String),
101
102 #[error(transparent)]
103 ProfileError(#[from] scouter_types::error::ProfileError),
104
105 #[error("Failed to process GenAI drift record: {0}")]
106 GenAIEvaluatorError(String),
107
108 #[error("Task not found: {0}")]
109 TaskNotFound(String),
110
111 #[error("Failed to acquire read lock on workflow")]
112 ReadLockAcquireError,
113
114 #[error("Invalid email validation operation")]
115 InvalidEmailOperation,
116
117 #[error("Invalid URL validation operation")]
118 InvalidUrlOperation,
119
120 #[error("Invalid UUID validation operation")]
121 InvalidUuidOperation,
122
123 #[error("Invalid ISO8601 validation operation")]
124 InvalidIso8601Operation,
125
126 #[error("Invalid JSON validation operation")]
127 InvalidJsonOperation,
128
129 #[error("Invalid range format - expected [min, max] array")]
130 InvalidRangeFormat,
131
132 #[error("Invalid tolerance format - expected [value, tolerance] array")]
133 InvalidToleranceFormat,
134
135 #[error("Invalid ContainsAll operation")]
136 InvalidContainsAllOperation,
137
138 #[error("Invalid ContainsAny operation")]
139 InvalidContainsAnyOperation,
140
141 #[error("Invalid ContainsNone operation")]
142 InvalidContainsNoneOperation,
143
144 #[error("Invalid empty check operation")]
145 InvalidEmptyOperation,
146
147 #[error("Invalid unique items check operation")]
148 InvalidUniqueItemsOperation,
149
150 #[error("Invalid alphabetic check operation")]
151 InvalidAlphabeticOperation,
152
153 #[error("Invalid alphanumeric check operation")]
154 InvalidAlphanumericOperation,
155
156 #[error("Invalid case check operation")]
157 InvalidCaseOperation,
158
159 #[error("Invalid contains word operation")]
160 InvalidContainsWordOperation,
161
162 #[error(transparent)]
163 RecordError(#[from] scouter_types::error::RecordError),
164
165 #[error("Array {index} out of bounds for length {length}")]
166 IndexOutOfBounds { index: isize, length: usize },
167
168 #[error("Expected an integer index or a slice")]
169 IndexOrSliceExpected,
170
171 #[error("Invalid sequence matches operation")]
172 InvalidSequenceMatchesOperation,
173
174 #[error("Invalid filter: {0}")]
175 InvalidFilter(String),
176
177 #[error("Trace data has no spans")]
178 NoRootSpan,
179
180 #[error("Attribute '{0}' not found in span")]
181 AttributeNotFound(String),
182}
183
184impl From<pythonize::PythonizeError> for EvaluationError {
185 fn from(err: PythonizeError) -> Self {
186 EvaluationError::PyError(err.to_string())
187 }
188}
189
190impl<'a, 'py> From<pyo3::CastError<'a, 'py>> for EvaluationError {
191 fn from(err: pyo3::CastError) -> Self {
192 EvaluationError::DowncastError(err.to_string())
193 }
194}
195
196impl From<EvaluationError> for PyErr {
197 fn from(err: EvaluationError) -> PyErr {
198 let msg = err.to_string();
199 error!("{}", msg);
200 PyRuntimeError::new_err(msg)
201 }
202}
203
204impl From<PyErr> for EvaluationError {
205 fn from(err: PyErr) -> EvaluationError {
206 EvaluationError::PyError(err.to_string())
207 }
208}
209
210impl<'a, 'py> From<PyClassGuardError<'a, 'py>> for EvaluationError {
211 fn from(err: PyClassGuardError<'a, 'py>) -> Self {
212 EvaluationError::PyError(err.to_string())
213 }
214}