Skip to content

Error Handling

Finance Query uses a single FinanceError enum for all error cases. Every library method returns Result<T, FinanceError>.

Error Variants

Variant When it occurs Retriable
AuthenticationFailed Yahoo crumb/cookie auth failure, EDGAR init rejected
SymbolNotFound Ticker symbol doesn't exist or returned no data
RateLimited Provider rate limit exceeded
HttpError Transport-level HTTP failure (DNS, TLS, connection refused)
JsonParseError Provider returned malformed JSON
ResponseStructureError Missing or malformed response fields
InvalidParameter Bad input: invalid symbols, unsupported interval/range combo
Timeout Request timed out
ServerError Provider returned 5xx status
UnexpectedResponse Unexpected API response format
InternalError Internal library error
ApiError Generic API-level error
RuntimeError Tokio I/O error
MacroDataError FRED / Treasury data fetch or parse failure
FeedParseError RSS/Atom feed parse failure
NotSupported Provider doesn't support the requested operation
NoProviderAvailable No configured provider supports this operation

Checking Error Types

use finance_query::FinanceError;

match &error {
    FinanceError::RateLimited { retry_after } => {
        if let Some(secs) = retry_after {
            tokio::time::sleep(std::time::Duration::from_secs(*secs)).await;
        }
    }
    FinanceError::SymbolNotFound { symbol, .. } => {
        eprintln!("Symbol not found: {:?}", symbol);
    }
    _ => eprintln!("{}", error),
}

Retry Logic

Use is_retriable() and retry_after_secs() to implement exponential backoff:

use finance_query::FinanceError;

fn should_retry(error: &FinanceError, attempt: u32) -> bool {
    if !error.is_retriable() || attempt > 3 {
        return false;
    }
    true
}

fn retry_delay(error: &FinanceError) -> std::time::Duration {
    let base = error.retry_after_secs().unwrap_or(1);
    std::time::Duration::from_secs(base)
}

The built-in retriable variants are RateLimited, Timeout, HttpError, AuthenticationFailed, ServerError, and RuntimeError.

Error Categorization

Use category() for logging and metrics:

use finance_query::{FinanceError, ErrorCategory};

match error.category() {
    ErrorCategory::Auth => tracing::warn!("Auth failure"),
    ErrorCategory::RateLimit => tracing::warn!("Rate limited, backing off"),
    ErrorCategory::Timeout => tracing::warn!("Timeout"),
    ErrorCategory::Server => tracing::error!("Upstream server error"),
    ErrorCategory::NotFound => tracing::info!("Symbol not found"),
    ErrorCategory::Validation => tracing::warn!("Invalid input: {}", error),
    ErrorCategory::Parsing => tracing::error!("Parse failure"),
    ErrorCategory::Other => tracing::error!("{}", error),
}

Adding Context

Enrich errors with symbol and context using the fluent API:

use finance_query::FinanceError;

let error = FinanceError::SymbolNotFound {
    symbol: None,
    context: String::new(),
}
.with_symbol("AAPL")
.with_context("from batch quote fetch");

with_symbol() only sets the symbol on SymbolNotFound errors. with_context() sets context on AuthenticationFailed, SymbolNotFound, ResponseStructureError, and ServerError.

Batch Response Errors

When using Tickers, per-symbol errors are stored in the response rather than returned as Result::Err:

let response = tickers.quotes().await?;

// Successful fetch — but individual symbols may have failed
for (symbol, error_str) in &response.errors {
    eprintln!("{}: {}", symbol, error_str);
}

// Convenience methods
println!("Success: {}, Failed: {}", response.success_count(), response.error_count());
if !response.all_successful() {
    eprintln!("Some symbols failed");
}

Provider-Specific Errors

When using multiple providers, NotSupported and NoProviderAvailable help diagnose missing capabilities:

match &error {
    FinanceError::NotSupported { provider, operation } => {
        // AlphaVantage doesn't do options — expected
        eprintln!("{} does not support {}", provider, operation);
    }
    FinanceError::NoProviderAvailable { operation } => {
        // No configured provider supports this operation
        eprintln!("No provider available for {}", operation);
    }
    _ => {}
}