pub type Result<T> = std::result::Result<T, ClaudeSDKError>;
#[derive(Debug, thiserror::Error)]
pub enum ClaudeSDKError {
#[error(
"Claude Code CLI not found. Install with: npm install -g @anthropic-ai/claude-code\n\
If already installed, ensure it's in PATH or set cli_path in options."
)]
CLINotFound,
#[error("Failed to connect to Claude Code: {0}")]
CLIConnection(String),
#[error(
"Claude Code version {found} is below minimum required version {minimum}.\n\
Update with: npm update -g @anthropic-ai/claude-code"
)]
CLIVersionTooOld { found: String, minimum: String },
#[error("CLI process failed with exit code {exit_code}: {message}{}", .stderr.as_ref().map(|s| format!("\nStderr: {}", s)).unwrap_or_default())]
Process {
exit_code: i32,
message: String,
stderr: Option<String>,
},
#[error("Failed to parse JSON from CLI: {0}")]
JSONDecode(#[from] serde_json::Error),
#[error("Failed to parse message: {0}")]
MessageParse(String),
#[error("Transport not ready for communication. Process may not be started.")]
TransportNotReady,
#[error("Not connected. Call connect() before attempting operations.")]
NotConnected,
#[error("Already connected. Disconnect first before reconnecting.")]
AlreadyConnected,
#[error("Control request timed out after {timeout_secs} seconds: {request_type}")]
ControlTimeout {
timeout_secs: u64,
request_type: String,
},
#[error("Hook callback not found: {0}")]
HookNotFound(String),
#[error("Permission callback (can_use_tool) is not set but is required for this operation.")]
PermissionCallbackNotSet,
#[error("MCP server '{0}' not found in configuration.")]
McpServerNotFound(String),
#[error("Invalid configuration: {0}")]
InvalidConfig(String),
#[error(
"JSON buffer exceeded maximum size of {max_size} bytes. Message may be truncated or malformed."
)]
BufferOverflow { max_size: usize },
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Authentication error: {0}")]
AuthenticationError(String),
#[error("Network error: {0}")]
NetworkError(String),
#[error("Parse error: {0}")]
ParseError(String),
#[error("Unknown message type: {0}")]
UnknownMessageType(String),
#[error("{0}")]
Other(String),
}
impl ClaudeSDKError {
pub fn connection<S: Into<String>>(msg: S) -> Self {
Self::CLIConnection(msg.into())
}
pub fn process(exit_code: i32, message: String, stderr: Option<String>) -> Self {
Self::Process {
exit_code,
message,
stderr,
}
}
pub fn message_parse<S: Into<String>>(msg: S) -> Self {
Self::MessageParse(msg.into())
}
pub fn control_timeout(timeout_secs: u64, request_type: String) -> Self {
Self::ControlTimeout {
timeout_secs,
request_type,
}
}
pub fn invalid_config<S: Into<String>>(msg: S) -> Self {
Self::InvalidConfig(msg.into())
}
pub fn buffer_overflow(max_size: usize) -> Self {
Self::BufferOverflow { max_size }
}
pub fn other<S: Into<String>>(msg: S) -> Self {
Self::Other(msg.into())
}
}
impl From<String> for ClaudeSDKError {
fn from(s: String) -> Self {
Self::Other(s)
}
}
impl From<&str> for ClaudeSDKError {
fn from(s: &str) -> Self {
Self::Other(s.to_string())
}
}