Skip to main content

Error Handling

This guide covers error handling patterns for the Privacy Boost CLI. For the cross-platform error code reference, see Error Handling.

CliError

All SDK operations return Result<T, CliError>:
pub enum CliError {
    NotConnected,
    NotAuthenticated,
    InvalidConfig { message: String },
    InvalidPrivateKey { message: String },
    NetworkError { message: String },
    WalletError { message: String },
    SigningError { message: String },
    TransactionFailed { message: String },
    InsufficientBalance,
    InvalidAddress,
    InvalidAmount,
    SerializationError { message: String },
    InternalError { message: String },
    ConfigFileError { message: String },
}

Basic Error Handling

match sdk.shield(token_address, amount) {
    Ok(result) => {
        println!("Deposit TX: {}", result.tx_hash);
    }
    Err(CliError::NotAuthenticated) => {
        println!("Please run 'privacy-boost login' first");
    }
    Err(CliError::InsufficientBalance) => {
        println!("Not enough tokens in wallet");
    }
    Err(CliError::InvalidAmount) => {
        println!("Invalid amount format");
    }
    Err(CliError::NetworkError { message }) => {
        println!("Network error: {}", message);
    }
    Err(e) => {
        println!("Deposit failed: {:?}", e);
    }
}

CLI Error Messages

Common CLI error outputs:
Error: Not authenticated. Run 'privacy-boost login' first.
Error: Insufficient shielded balance. Have: 0.5 ETH, Need: 1.0 ETH
Error: Invalid privacy address format.
Error: Failed to connect to indexer at https://...
Error: Invalid private key format.

Retry Pattern

For network errors, use a retry loop:
fn with_retry<T, F>(max_retries: u32, operation: F) -> Result<T, CliError>
where
    F: Fn() -> Result<T, CliError>,
{
    for attempt in 1..=max_retries {
        match operation() {
            Ok(result) => return Ok(result),
            Err(CliError::NetworkError { .. }) if attempt < max_retries => {
                let delay = std::time::Duration::from_secs(attempt as u64);
                std::thread::sleep(delay);
                continue;
            }
            Err(e) => return Err(e),
        }
    }
    operation()
}

// Usage
let balance = with_retry(3, || sdk.get_balance(token_address))?;

Categorizing Errors

enum ErrorCategory {
    UserAction,  // User can fix (login, add funds)
    Retryable,   // Transient, retry may work
    Fatal,       // Requires developer attention
}

fn categorize(error: &CliError) -> ErrorCategory {
    match error {
        CliError::NotConnected
        | CliError::NotAuthenticated
        | CliError::InsufficientBalance
        | CliError::InvalidAddress
        | CliError::InvalidAmount
        | CliError::InvalidPrivateKey { .. } => ErrorCategory::UserAction,

        CliError::NetworkError { .. } => ErrorCategory::Retryable,

        _ => ErrorCategory::Fatal,
    }
}

User-Friendly Error Messages

fn user_message(error: &CliError) -> String {
    match error {
        CliError::NotConnected => "Wallet not connected".into(),
        CliError::NotAuthenticated => "Please run 'privacy-boost login' first".into(),
        CliError::InsufficientBalance => "Not enough balance".into(),
        CliError::InvalidAddress => "Invalid address format".into(),
        CliError::InvalidAmount => "Invalid amount format".into(),
        CliError::InvalidPrivateKey { message } => format!("Invalid private key: {}", message),
        CliError::NetworkError { message } => format!("Network error: {}", message),
        CliError::ConfigFileError { message } => format!("Config error: {}", message),
        _ => "An unexpected error occurred".into(),
    }
}

Best Practices

1. Always Match on Specific Errors

match sdk.shield(token, amount) {
    Ok(result) => println!("Success: {}", result.tx_hash),
    Err(CliError::InsufficientBalance) => {
        eprintln!("Not enough balance. Check with: privacy-boost balance --token {}", token);
    }
    Err(e) => eprintln!("Error: {}", user_message(&e)),
}

2. Log Errors for Debugging

match sdk.shield(token, amount) {
    Ok(result) => println!("Deposit TX: {}", result.tx_hash),
    Err(e) => {
        eprintln!("[DEBUG] {:?}", e);
        eprintln!("{}", user_message(&e));
    }
}

3. Handle Network Errors with Retry

Network errors are transient. Use the retry pattern for automated scripts.

Next Steps