//! Error types for the Claude Agent SDK. //! //! Mirrors the exception hierarchy in the upstream Python SDK //! (`claude_agent_sdk._errors`): //! //! - [`Error::CliNotFound`] — `CLINotFoundError` //! - [`Error::CliConnection`] — `CLIConnectionError` //! - [`Error::Process`] — `ProcessError` //! - [`Error::JsonDecode`] — `CLIJSONDecodeError` //! - [`Error::MessageParse`] — `MessageParseError` //! //! All variants inherit from `ClaudeSDKError` in Python; in Rust we expose a //! single `Error` enum and rely on pattern matching (or [`Error::kind`]) to //! distinguish them. use thiserror::Error; /// All errors surfaced by the SDK. /// /// The Python SDK uses an exception hierarchy rooted at `ClaudeSDKError`. We /// flatten that into a single enum because Rust pattern matching is more /// ergonomic than `try`/`except` chains, and because most callers only care /// about a small subset (e.g. "did the CLI not exist?" vs everything else). #[derive(Debug, Error)] pub enum Error { /// The `claude` CLI binary could not be located on `PATH` or in any of the /// fallback search locations, and no explicit `cli_path` was supplied via /// [`crate::ClaudeAgentOptions::cli_path`]. /// /// Mirrors Python's `CLINotFoundError`. #[error("{0}")] CliNotFound(String), /// Generic connection / transport problem with the CLI subprocess — /// failed to spawn, stdin write failed, transport not ready, etc. /// /// Mirrors Python's `CLIConnectionError`. #[error("{0}")] CliConnection(String), /// The CLI subprocess exited with a non-zero status before yielding a /// `ResultMessage`. /// /// Mirrors Python's `ProcessError`. #[error("{message}{exit_code}{stderr}", exit_code = match exit_code { Some(c) => format!(" (exit code: {c})"), None => String::new() }, stderr = match stderr { Some(s) if !s.is_empty() => format!("\nError output: {s}"), _ => String::new() }, )] Process { /// Human-readable description (e.g. `"Command failed"`). message: String, /// Subprocess exit code, when known. exit_code: Option, /// Captured stderr output, when stderr was piped via /// [`crate::ClaudeAgentOptions::capture_stderr`]. stderr: Option, }, /// A line on the CLI's stdout could not be decoded as JSON even after /// buffering up to `max_buffer_size` bytes. /// /// Mirrors Python's `CLIJSONDecodeError`. #[error("Failed to decode JSON: {line_preview}...")] JsonDecode { /// First ~100 chars of the offending line, included in the message. line_preview: String, /// The underlying serde error. #[source] source: serde_json::Error, }, /// A JSON message from the CLI was decoded but did not match any known /// shape, or was missing a required field. /// /// Mirrors Python's `MessageParseError`. #[error("Message parse error: {message}")] MessageParse { /// Human-readable description. message: String, /// The raw JSON value the parser was looking at, if available. data: Option, }, /// Underlying I/O failure (rare — most I/O is surfaced as /// [`Error::CliConnection`]). #[error("io error: {0}")] Io(#[from] std::io::Error), /// Invalid configuration (e.g. mutually exclusive options). #[error("invalid configuration: {0}")] Config(String), } impl Error { /// Construct a [`Error::CliConnection`] from any displayable value. pub(crate) fn conn(msg: impl Into) -> Self { Self::CliConnection(msg.into()) } /// Construct a [`Error::MessageParse`] with raw data attached. pub(crate) fn parse_with_data(msg: impl Into, data: serde_json::Value) -> Self { Self::MessageParse { message: msg.into(), data: Some(data), } } } /// Convenience alias for `Result`. pub type Result = std::result::Result;