atento_core/
errors.rs

1use serde::Serialize;
2use std::fmt;
3
4/// The main error type for the Atento chain engine.
5#[derive(Debug, Serialize)]
6#[serde(tag = "type", content = "data")]
7pub enum AtentoError {
8    /// I/O error when reading files
9    Io {
10        path: String,
11        #[serde(serialize_with = "serialize_io_error")]
12        source: std::io::Error,
13    },
14
15    /// YAML parsing error
16    YamlParse {
17        context: String,
18        #[serde(serialize_with = "serialize_yaml_error")]
19        source: serde_yaml::Error,
20    },
21
22    /// JSON serialization error
23    JsonSerialize { message: String },
24
25    /// Chain validation error
26    Validation(String),
27
28    /// Chain execution error
29    Execution(String),
30
31    /// Step execution error
32    StepExecution { step: String, reason: String },
33
34    /// Data type conversion error
35    TypeConversion { expected: String, got: String },
36
37    /// Reference resolution error
38    UnresolvedReference { reference: String, context: String },
39
40    /// Timeout error
41    Timeout { context: String, timeout_secs: u64 },
42
43    /// Script runner error
44    Runner(String),
45}
46
47// Custom serializers for non-serializable error types
48fn serialize_io_error<S>(
49    error: &std::io::Error,
50    serializer: S,
51) -> std::result::Result<S::Ok, S::Error>
52where
53    S: serde::Serializer,
54{
55    serializer.serialize_str(&error.to_string())
56}
57
58fn serialize_yaml_error<S>(
59    error: &serde_yaml::Error,
60    serializer: S,
61) -> std::result::Result<S::Ok, S::Error>
62where
63    S: serde::Serializer,
64{
65    serializer.serialize_str(&error.to_string())
66}
67
68// Note: JsonSerialize variant stores a message string, see From impl below.
69
70impl fmt::Display for AtentoError {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            Self::Io { path, source } => {
74                write!(f, "Failed to read file '{path}': {source}")
75            }
76            Self::YamlParse { context, source } => {
77                write!(f, "Failed to parse YAML in '{context}': {source}")
78            }
79            Self::JsonSerialize { message } => {
80                write!(f, "Failed to serialize results: {message}")
81            }
82            Self::Validation(msg) => {
83                write!(f, "Chain validation failed: {msg}")
84            }
85            Self::Execution(msg) => {
86                write!(f, "Chain execution failed: {msg}")
87            }
88            Self::StepExecution { step, reason } => {
89                write!(f, "Step '{step}' failed: {reason}")
90            }
91            Self::TypeConversion { expected, got } => {
92                write!(f, "Expected {expected} value, got: {got}")
93            }
94            Self::UnresolvedReference { reference, context } => {
95                write!(f, "Unresolved reference '{reference}' in {context}")
96            }
97            Self::Timeout {
98                context,
99                timeout_secs,
100            } => {
101                write!(f, "{context} timeout after {timeout_secs}s")
102            }
103            Self::Runner(msg) => {
104                write!(f, "Runner error: {msg}")
105            }
106        }
107    }
108}
109
110impl std::error::Error for AtentoError {
111    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
112        match self {
113            Self::Io { source, .. } => Some(source),
114            Self::YamlParse { source, .. } => Some(source),
115            // JsonSerialize now contains a message string; no underlying error to return as source
116            _ => None,
117        }
118    }
119}
120
121impl From<serde_json::Error> for AtentoError {
122    fn from(err: serde_json::Error) -> Self {
123        Self::JsonSerialize {
124            message: err.to_string(),
125        }
126    }
127}
128
129/// Type alias for Results using `AtentoError`
130pub type Result<T> = std::result::Result<T, AtentoError>;