Skip to main content

claude_code/
errors.rs

1//! Error types for the Claude Code SDK.
2//!
3//! This module defines all error types that can occur during SDK operations,
4//! including connection failures, process errors, JSON parsing errors, and
5//! message parsing errors.
6
7use serde_json::Value;
8use thiserror::Error;
9
10/// General SDK error for validation and logic failures.
11///
12/// Used for errors that don't fit into more specific categories, such as
13/// invalid configuration or callback errors.
14#[derive(Debug, Error, Clone)]
15#[error("{message}")]
16pub struct ClaudeSDKError {
17    /// Human-readable error message.
18    pub message: String,
19}
20
21impl ClaudeSDKError {
22    /// Creates a new `ClaudeSDKError` with the given message.
23    ///
24    /// # Example
25    ///
26    /// ```rust
27    /// use claude_code::ClaudeSDKError;
28    ///
29    /// let err = ClaudeSDKError::new("invalid configuration");
30    /// assert_eq!(err.to_string(), "invalid configuration");
31    /// ```
32    pub fn new(message: impl Into<String>) -> Self {
33        Self {
34            message: message.into(),
35        }
36    }
37}
38
39/// Error establishing or maintaining a connection to the Claude Code CLI process.
40///
41/// Raised when the transport layer cannot connect, the process terminates
42/// unexpectedly, or stdin/stdout communication fails.
43#[derive(Debug, Error, Clone)]
44#[error("{message}")]
45pub struct CLIConnectionError {
46    /// Human-readable connection error message.
47    pub message: String,
48}
49
50impl CLIConnectionError {
51    /// Creates a new `CLIConnectionError` with the given message.
52    ///
53    /// # Example
54    ///
55    /// ```rust
56    /// use claude_code::CLIConnectionError;
57    ///
58    /// let err = CLIConnectionError::new("connection dropped");
59    /// assert!(err.to_string().contains("connection dropped"));
60    /// ```
61    pub fn new(message: impl Into<String>) -> Self {
62        Self {
63            message: message.into(),
64        }
65    }
66}
67
68/// Error when the Claude Code CLI executable cannot be found.
69///
70/// This error is raised if the CLI is not installed or not in the expected
71/// locations. Install Claude Code with `npm install -g @anthropic-ai/claude-code`,
72/// or provide a custom path via [`ClaudeAgentOptions::cli_path`](crate::ClaudeAgentOptions::cli_path).
73#[derive(Debug, Error, Clone)]
74#[error("{message}")]
75pub struct CLINotFoundError {
76    /// Human-readable not-found message.
77    pub message: String,
78    /// The path that was searched, if a specific path was configured.
79    pub cli_path: Option<String>,
80}
81
82impl CLINotFoundError {
83    /// Creates a new `CLINotFoundError` with the given message and optional path.
84    ///
85    /// # Example
86    ///
87    /// ```rust
88    /// use claude_code::CLINotFoundError;
89    ///
90    /// let err = CLINotFoundError::new("Claude Code not found", Some("/usr/local/bin/claude".to_string()));
91    /// assert!(err.to_string().contains("/usr/local/bin/claude"));
92    /// ```
93    pub fn new(message: impl Into<String>, cli_path: Option<String>) -> Self {
94        let base = message.into();
95        let message = match &cli_path {
96            Some(path) => format!("{base}: {path}"),
97            None => base,
98        };
99        Self { message, cli_path }
100    }
101}
102
103/// Error from the Claude Code CLI subprocess execution.
104///
105/// Contains the exit code and stderr output for debugging.
106#[derive(Debug, Error, Clone)]
107#[error("{message}")]
108pub struct ProcessError {
109    /// Human-readable process error message (may include code/stderr summary).
110    pub message: String,
111    /// The process exit code, if available.
112    pub exit_code: Option<i32>,
113    /// The stderr output from the process, if captured.
114    pub stderr: Option<String>,
115}
116
117impl ProcessError {
118    /// Creates a new `ProcessError` with the given message, exit code, and stderr.
119    ///
120    /// # Example
121    ///
122    /// ```rust
123    /// use claude_code::ProcessError;
124    ///
125    /// let err = ProcessError::new("Command failed", Some(1), Some("permission denied".to_string()));
126    /// assert!(err.to_string().contains("exit code: 1"));
127    /// ```
128    pub fn new(message: impl Into<String>, exit_code: Option<i32>, stderr: Option<String>) -> Self {
129        let base = message.into();
130        let mut message = base.clone();
131        if let Some(code) = exit_code {
132            message = format!("{message} (exit code: {code})");
133        }
134        if let Some(stderr_text) = &stderr {
135            message = format!("{message}\nError output: {stderr_text}");
136        }
137
138        Self {
139            message,
140            exit_code,
141            stderr,
142        }
143    }
144}
145
146/// Error decoding JSON from the CLI stdout stream.
147///
148/// Raised when the CLI outputs invalid JSON or when a JSON message exceeds
149/// the configured buffer size.
150#[derive(Debug, Error, Clone)]
151#[error("Failed to decode JSON: {preview}...")]
152pub struct CLIJSONDecodeError {
153    /// The raw line that failed to parse.
154    pub line: String,
155    /// The original parsing error description.
156    pub original_error: String,
157    /// A preview of the raw line (first 100 characters).
158    pub preview: String,
159}
160
161impl CLIJSONDecodeError {
162    /// Creates a new `CLIJSONDecodeError` with the raw line and error description.
163    ///
164    /// # Example
165    ///
166    /// ```rust
167    /// use claude_code::CLIJSONDecodeError;
168    ///
169    /// let err = CLIJSONDecodeError::new("{bad json}", "expected value");
170    /// assert!(err.preview.contains("{bad json}"));
171    /// ```
172    pub fn new(line: impl Into<String>, original_error: impl Into<String>) -> Self {
173        let line = line.into();
174        let preview: String = line.chars().take(100).collect();
175        Self {
176            line,
177            original_error: original_error.into(),
178            preview,
179        }
180    }
181}
182
183/// Error parsing a JSON message into a typed [`Message`](crate::Message).
184///
185/// Raised when a message from the CLI is missing required fields or
186/// has unexpected structure.
187#[derive(Debug, Error, Clone)]
188#[error("{message}")]
189pub struct MessageParseError {
190    /// Human-readable parse failure message.
191    pub message: String,
192    /// The raw JSON data that failed to parse, if available.
193    pub data: Option<Value>,
194}
195
196impl MessageParseError {
197    /// Creates a new `MessageParseError` with the given message and optional raw data.
198    ///
199    /// # Example
200    ///
201    /// ```rust
202    /// use claude_code::MessageParseError;
203    ///
204    /// let err = MessageParseError::new("missing field", None);
205    /// assert_eq!(err.to_string(), "missing field");
206    /// ```
207    pub fn new(message: impl Into<String>, data: Option<Value>) -> Self {
208        Self {
209            message: message.into(),
210            data,
211        }
212    }
213}
214
215/// Unified error type for all SDK operations.
216///
217/// This enum wraps all specific error types into a single type, enabling
218/// use of the `?` operator throughout the SDK.
219#[derive(Debug, Error)]
220pub enum Error {
221    /// General SDK error.
222    #[error(transparent)]
223    ClaudeSDK(#[from] ClaudeSDKError),
224    /// Connection error with the CLI process.
225    #[error(transparent)]
226    CLIConnection(#[from] CLIConnectionError),
227    /// CLI executable not found.
228    #[error(transparent)]
229    CLINotFound(#[from] CLINotFoundError),
230    /// CLI process execution error.
231    #[error(transparent)]
232    Process(#[from] ProcessError),
233    /// JSON decoding error from CLI output.
234    #[error(transparent)]
235    CLIJSONDecode(#[from] CLIJSONDecodeError),
236    /// Message parsing error.
237    #[error(transparent)]
238    MessageParse(#[from] MessageParseError),
239    /// Standard I/O error.
240    #[error(transparent)]
241    Io(#[from] std::io::Error),
242    /// JSON serialization/deserialization error.
243    #[error(transparent)]
244    Json(#[from] serde_json::Error),
245    /// Other errors not covered by specific variants.
246    #[error("{0}")]
247    Other(String),
248}
249
250/// A specialized `Result` type for SDK operations.
251pub type Result<T> = std::result::Result<T, Error>;