Skip to main content

adk_action/
error.rs

1//! Error types for action node execution.
2
3use thiserror::Error;
4
5/// Errors that can occur during action node execution.
6#[derive(Debug, Error)]
7pub enum ActionError {
8    /// HTTP response status did not match validation pattern.
9    #[error("HTTP status error: {status} for {url}")]
10    HttpStatus { status: u16, url: String },
11
12    /// Operation timed out.
13    #[error("Action timed out after {ms}ms: {context}")]
14    Timeout { ms: u64, context: String },
15
16    /// No switch condition matched and no default branch configured.
17    #[error("No matching branch for switch node '{node_id}'")]
18    NoMatchingBranch { node_id: String },
19
20    /// Transform operation failed.
21    #[error("Transform failed: {0}")]
22    Transform(String),
23
24    /// Code execution failed.
25    #[error("Code execution failed: {0}")]
26    CodeExecution(String),
27
28    /// Sandbox initialization failed.
29    #[error("Sandbox initialization failed: {0}")]
30    SandboxInit(String),
31
32    /// Missing credential reference.
33    #[error("Missing credential: {0}")]
34    MissingCredential(String),
35
36    /// No database connection available.
37    #[error("No database connection: {0}")]
38    NoDatabase(String),
39
40    /// Invalid timestamp format.
41    #[error("Invalid timestamp: {0}")]
42    InvalidTimestamp(String),
43
44    /// Webhook wait timed out.
45    #[error("Webhook wait timed out after {ms}ms")]
46    WebhookTimeout { ms: u64 },
47
48    /// Webhook was cancelled.
49    #[error("Webhook cancelled: {0}")]
50    WebhookCancelled(String),
51
52    /// Condition polling timed out.
53    #[error("Condition timed out after {ms}ms")]
54    ConditionTimeout { ms: u64 },
55
56    /// No branch completed in merge node.
57    #[error("No branch completed for merge node '{node_id}'")]
58    NoBranchCompleted { node_id: String },
59
60    /// Insufficient branches completed for waitN merge.
61    #[error("Insufficient branches: got {got}, need {need}")]
62    InsufficientBranches { got: u32, need: u32 },
63
64    /// Email authentication failed.
65    #[error("Email auth failed: {0}")]
66    EmailAuth(String),
67
68    /// Email send failed.
69    #[error("Email send failed: {0}")]
70    EmailSend(String),
71
72    /// Notification send failed.
73    #[error("Notification send failed: {0}")]
74    NotificationSend(String),
75
76    /// RSS feed fetch failed.
77    #[error("RSS fetch failed: {0}")]
78    RssFetch(String),
79
80    /// RSS feed parse failed.
81    #[error("RSS parse failed: {0}")]
82    RssParse(String),
83
84    /// File read failed.
85    #[error("File read failed: {0}")]
86    FileRead(String),
87
88    /// File write failed.
89    #[error("File write failed: {0}")]
90    FileWrite(String),
91
92    /// File delete failed.
93    #[error("File delete failed: {0}")]
94    FileDelete(String),
95
96    /// File parse failed.
97    #[error("File parse failed: {0}")]
98    FileParse(String),
99
100    /// Catch-all for other errors.
101    #[error("{0}")]
102    Other(String),
103}
104
105impl From<ActionError> for adk_core::AdkError {
106    fn from(err: ActionError) -> Self {
107        use adk_core::{ErrorCategory, ErrorComponent};
108
109        let (category, code) = match &err {
110            ActionError::HttpStatus { .. } => (ErrorCategory::Internal, "action.http_status"),
111            ActionError::Timeout { .. } => (ErrorCategory::Timeout, "action.timeout"),
112            ActionError::NoMatchingBranch { .. } => {
113                (ErrorCategory::InvalidInput, "action.no_matching_branch")
114            }
115            ActionError::Transform(_) => (ErrorCategory::Internal, "action.transform"),
116            ActionError::CodeExecution(_) => (ErrorCategory::Internal, "action.code_execution"),
117            ActionError::SandboxInit(_) => (ErrorCategory::Internal, "action.sandbox_init"),
118            ActionError::MissingCredential(_) => {
119                (ErrorCategory::Unauthorized, "action.missing_credential")
120            }
121            ActionError::NoDatabase(_) => (ErrorCategory::Unavailable, "action.no_database"),
122            ActionError::InvalidTimestamp(_) => {
123                (ErrorCategory::InvalidInput, "action.invalid_timestamp")
124            }
125            ActionError::WebhookTimeout { .. } => {
126                (ErrorCategory::Timeout, "action.webhook_timeout")
127            }
128            ActionError::WebhookCancelled(_) => {
129                (ErrorCategory::Cancelled, "action.webhook_cancelled")
130            }
131            ActionError::ConditionTimeout { .. } => {
132                (ErrorCategory::Timeout, "action.condition_timeout")
133            }
134            ActionError::NoBranchCompleted { .. } => {
135                (ErrorCategory::Internal, "action.no_branch_completed")
136            }
137            ActionError::InsufficientBranches { .. } => {
138                (ErrorCategory::Internal, "action.insufficient_branches")
139            }
140            ActionError::EmailAuth(_) => (ErrorCategory::Unauthorized, "action.email_auth"),
141            ActionError::EmailSend(_) => (ErrorCategory::Internal, "action.email_send"),
142            ActionError::NotificationSend(_) => {
143                (ErrorCategory::Internal, "action.notification_send")
144            }
145            ActionError::RssFetch(_) => (ErrorCategory::Unavailable, "action.rss_fetch"),
146            ActionError::RssParse(_) => (ErrorCategory::Internal, "action.rss_parse"),
147            ActionError::FileRead(_) => (ErrorCategory::Internal, "action.file_read"),
148            ActionError::FileWrite(_) => (ErrorCategory::Internal, "action.file_write"),
149            ActionError::FileDelete(_) => (ErrorCategory::Internal, "action.file_delete"),
150            ActionError::FileParse(_) => (ErrorCategory::Internal, "action.file_parse"),
151            ActionError::Other(_) => (ErrorCategory::Internal, "action.other"),
152        };
153
154        adk_core::AdkError::new(ErrorComponent::Graph, category, code, err.to_string())
155            .with_source(err)
156    }
157}