This guide documents exception hierarchies and error handling patterns in fin-infra.
Exception Hierarchy
code
Exception
└── FinInfraError (base for all fin-infra exceptions)
├── ProviderError
│ ├── ProviderNotFoundError
│ ├── ProviderConfigError
│ └── ProviderAPIError
├── BankingError
│ ├── InvalidAccessTokenError
│ ├── InstitutionNotFoundError
│ ├── AccountNotFoundError
│ └── TransactionSyncError
├── BrokerageError
│ ├── OrderRejectedError
│ ├── InsufficientFundsError
│ ├── MarketClosedError
│ └── PositionNotFoundError
├── MarketDataError
│ ├── SymbolNotFoundError
│ ├── QuoteUnavailableError
│ └── RateLimitExceededError
├── CreditError
│ ├── CreditPullFailedError
│ └── ConsentRequiredError
└── CalculationError
├── InvalidCashFlowError
└── DivisionByZeroErrorCritical: Financial Error Handling
Never Silently Fail on Money Operations
python
# ❌ WRONG - User's net worth is wrong
for asset in assets:
if asset.currency != base_currency:
continue # Silent skip!
total += asset.value
# ✅ CORRECT - Fail loudly or handle explicitly
for asset in assets:
if asset.currency != base_currency:
raise UnsupportedCurrencyError(f"Currency {asset.currency} not supported")
# OR: converted = await convert_currency(asset, base_currency)Preserve Error Context for Auditing
python
try:
order = await submit_order(symbol, quantity)
except OrderRejectedError as e:
# Log for audit trail
audit_log.record(
action="order_rejected",
symbol=symbol,
quantity=quantity,
reason=str(e),
timestamp=datetime.utcnow(),
)
raiseIdempotency Errors
python
from fin_infra.exceptions import DuplicateOrderError
try:
order = await submit_order(symbol, qty, client_order_id)
except DuplicateOrderError:
# Idempotency: return existing order instead of error
order = await get_order_by_client_id(client_order_id)
return orderProvider-Specific Errors
Plaid Errors
python
from fin_infra.banking.exceptions import PlaidError
try:
accounts = await banking.get_accounts(access_token)
except PlaidError as e:
if e.error_code == "ITEM_LOGIN_REQUIRED":
# User needs to re-authenticate
return redirect_to_plaid_link()
raiseBrokerage Errors
python
from fin_infra.brokerage.exceptions import (
InsufficientFundsError,
MarketClosedError,
)
try:
order = await brokerage.submit_order(...)
except InsufficientFundsError:
return {"error": "Not enough buying power"}
except MarketClosedError:
return {"error": "Market is closed. Order queued."}HTTP Status Code Mapping
| Exception | HTTP Status |
|---|---|
| InvalidAccessTokenError | 401 |
| SymbolNotFoundError | 404 |
| InsufficientFundsError | 400 |
| RateLimitExceededError | 429 |
| ProviderAPIError | 502 |
| CalculationError | 500 |
Best Practices
- Log all financial operations for audit trail
- Never swallow exceptions in money calculations
- Use Decimal to avoid precision errors
- Add circuit breakers for external API calls
- Validate idempotency keys before operations