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 returnResult<T, CliError>:
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 },
}
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);
}
}
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.
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))?;
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,
}
}
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(),
}
}
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)),
}
match sdk.shield(token, amount) {
Ok(result) => println!("Deposit TX: {}", result.tx_hash),
Err(e) => {
eprintln!("[DEBUG] {:?}", e);
eprintln!("{}", user_message(&e));
}
}