claude_code_sdk/
errors.rs1use thiserror::Error;
4use tracing::error;
5use crate::config::SafetyError;
6
7#[derive(Error, Debug)]
9pub enum ClaudeSDKError {
10 #[error("CLI connection error: {0}")]
11 CLIConnection(#[from] CLIConnectionError),
12
13 #[error("CLI not found: {0}")]
14 CLINotFound(#[from] CLINotFoundError),
15
16 #[error("Process error: {0}")]
17 Process(#[from] ProcessError),
18
19 #[error("JSON decode error: {0}")]
20 CLIJSONDecode(#[from] CLIJSONDecodeError),
21
22 #[error("IO error: {0}")]
23 Io(#[from] std::io::Error),
24
25 #[error("Safety limit violation: {0}")]
26 Safety(#[from] SafetyError),
27
28 #[error("Other error: {0}")]
29 Other(String),
30}
31
32#[derive(Error, Debug)]
34#[error("Unable to connect to Claude Code: {message}")]
35pub struct CLIConnectionError {
36 pub message: String,
37}
38
39impl CLIConnectionError {
40 pub fn new(message: impl Into<String>) -> Self {
41 let message_str = message.into();
42 error!(message = %message_str, "CLI connection error occurred");
43 Self {
44 message: message_str,
45 }
46 }
47}
48
49#[derive(Error, Debug)]
51#[error("Claude Code not found: {message}")]
52pub struct CLINotFoundError {
53 pub message: String,
54 pub cli_path: Option<String>,
55}
56
57impl CLINotFoundError {
58 pub fn new(message: impl Into<String>) -> Self {
59 let message_str = message.into();
60 error!(message = %message_str, "Claude CLI not found");
61 Self {
62 message: message_str,
63 cli_path: None,
64 }
65 }
66
67 pub fn with_path(message: impl Into<String>, cli_path: impl Into<String>) -> Self {
68 let cli_path_string = cli_path.into();
69 let message_str = message.into();
70 error!(
71 message = %message_str,
72 cli_path = %cli_path_string,
73 "Claude CLI not found at specified path"
74 );
75 Self {
76 message: format!("{}: {}", message_str, cli_path_string),
77 cli_path: Some(cli_path_string),
78 }
79 }
80}
81
82#[derive(Error, Debug)]
84pub struct ProcessError {
85 pub message: String,
86 pub exit_code: Option<i32>,
87 pub stderr: Option<String>,
88}
89
90impl ProcessError {
91 pub fn new(message: impl Into<String>) -> Self {
92 let message_str = message.into();
93 error!(message = %message_str, "Process error occurred");
94 Self {
95 message: message_str,
96 exit_code: None,
97 stderr: None,
98 }
99 }
100
101 pub fn with_exit_code(message: impl Into<String>, exit_code: i32) -> Self {
102 let message_str = message.into();
103 error!(
104 message = %message_str,
105 exit_code = exit_code,
106 "Process error with exit code"
107 );
108 Self {
109 message: message_str,
110 exit_code: Some(exit_code),
111 stderr: None,
112 }
113 }
114
115 pub fn with_stderr(message: impl Into<String>, exit_code: Option<i32>, stderr: impl Into<String>) -> Self {
116 let message_str = message.into();
117 let stderr_str = stderr.into();
118 error!(
119 message = %message_str,
120 exit_code = exit_code,
121 stderr_preview = %stderr_str.chars().take(200).collect::<String>(),
122 "Process error with stderr output"
123 );
124 Self {
125 message: message_str,
126 exit_code,
127 stderr: Some(stderr_str),
128 }
129 }
130}
131
132impl std::fmt::Display for ProcessError {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 write!(f, "{}", self.message)?;
135
136 if let Some(exit_code) = self.exit_code {
137 write!(f, " (exit code: {})", exit_code)?;
138 }
139
140 if let Some(stderr) = &self.stderr {
141 write!(f, "\nError output: {}", stderr)?;
142 }
143
144 Ok(())
145 }
146}
147
148#[derive(Error, Debug)]
150pub struct CLIJSONDecodeError {
151 pub line: String,
152 pub original_error: serde_json::Error,
153}
154
155impl CLIJSONDecodeError {
156 pub fn new(line: impl Into<String>, original_error: serde_json::Error) -> Self {
157 let line_str = line.into();
158 error!(
159 line_preview = %line_str.chars().take(100).collect::<String>(),
160 parse_error = %original_error,
161 "Failed to decode JSON from CLI output"
162 );
163 Self {
164 line: line_str,
165 original_error,
166 }
167 }
168}
169
170impl std::fmt::Display for CLIJSONDecodeError {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 let line_preview = if self.line.len() > 100 {
173 format!("{}...", &self.line[..100])
174 } else {
175 self.line.clone()
176 };
177
178 write!(f, "Failed to decode JSON: {}", line_preview)
179 }
180}