Exceptions¶
GridFIA provides a hierarchy of domain-specific exceptions for clear, actionable error handling.
All exceptions inherit from GridFIAException, allowing you to catch any GridFIA error
with a single except clause.
Exception Hierarchy¶
GridFIAException (base)
├── InvalidZarrStructure # Zarr store validation errors
├── SpeciesNotFound # Species code resolution errors
├── CalculationFailed # Calculation execution errors
├── APIConnectionError # Network/API errors
├── InvalidLocationConfig # Geographic configuration errors
├── DownloadError # Data download failures
└── CircuitBreakerOpen # Service protection (circuit breaker)
Quick Reference¶
| Exception | Raised When |
|---|---|
GridFIAException |
Base class for all GridFIA errors |
InvalidZarrStructure |
Zarr store is corrupt or missing required data |
SpeciesNotFound |
Requested species code doesn't exist |
CalculationFailed |
Calculation encounters an error |
APIConnectionError |
FIA BIGMAP service connection fails |
InvalidLocationConfig |
State/county/bbox configuration is invalid |
DownloadError |
Raster download fails |
CircuitBreakerOpen |
Too many consecutive failures |
Usage Examples¶
Catching All GridFIA Errors¶
from gridfia import GridFIA, GridFIAException
api = GridFIA()
try:
results = api.calculate_metrics("data.zarr")
except GridFIAException as e:
print(f"GridFIA error: {e.message}")
print(f"Details: {e.details}")
Specific Error Handling¶
from gridfia import GridFIA
from gridfia.exceptions import (
InvalidZarrStructure,
SpeciesNotFound,
CalculationFailed,
APIConnectionError,
InvalidLocationConfig,
DownloadError,
CircuitBreakerOpen,
)
api = GridFIA()
try:
# Attempt download
files = api.download_species(
state="Montana",
species_codes=["0202"]
)
# Create Zarr
zarr_path = api.create_zarr("downloads/", "data.zarr")
# Calculate metrics
results = api.calculate_metrics(zarr_path)
except InvalidLocationConfig as e:
print(f"Location error: {e.message}")
print(f" State: {e.state}")
print(f" County: {e.county}")
except SpeciesNotFound as e:
print(f"Species not found: {e.species_code}")
if e.available_species:
print(f" Available: {e.available_species[:5]}...")
except DownloadError as e:
print(f"Download failed: {e.message}")
print(f" Species: {e.species_code}")
print(f" Output: {e.output_path}")
except APIConnectionError as e:
print(f"API error: {e.message}")
print(f" URL: {e.url}")
print(f" Status: {e.status_code}")
except CircuitBreakerOpen as e:
print(f"Service unavailable: {e.message}")
print(f" Retry after: {e.retry_after} seconds")
except InvalidZarrStructure as e:
print(f"Invalid Zarr: {e.message}")
print(f" Path: {e.zarr_path}")
print(f" Missing: {e.missing_attrs}")
except CalculationFailed as e:
print(f"Calculation error: {e.message}")
print(f" Calculation: {e.calculation_name}")
print(f" Available: {e.available_calculations}")
Exception Reference¶
GridFIAException¶
Bases: Exception
Base exception for all GridFIA errors.
All GridFIA-specific exceptions inherit from this class, making it easy to catch any GridFIA error with a single except clause.
Examples¶
try: ... api.calculate_metrics("invalid.zarr") ... except GridFIAException as e: ... print(f"GridFIA error: {e}")
Initialize the exception.
Parameters¶
message : str Human-readable error message details : dict, optional Additional context about the error
InvalidZarrStructure¶
Bases: GridFIAException
Raised when Zarr array has invalid structure or missing attributes.
This exception is raised when: - The Zarr store cannot be opened - Required arrays (biomass, species_codes) are missing - Array dimensions are incorrect - Required metadata attributes are missing
Examples¶
try: ... api.calculate_metrics("corrupt.zarr") ... except InvalidZarrStructure as e: ... print(f"Invalid Zarr: {e}")
SpeciesNotFound¶
Bases: GridFIAException
Raised when requested species code is not found.
This exception is raised when: - A species code does not exist in the FIA BIGMAP service - A species code is not present in a Zarr store - No raster function matches the requested species
Examples¶
try: ... api.download_species(state="MT", species_codes=["9999"]) ... except SpeciesNotFound as e: ... print(f"Species not found: {e}")
CalculationFailed¶
Bases: GridFIAException
Raised when a calculation fails to complete.
This exception is raised when: - A registered calculation encounters an error - Input data validation fails for a calculation - The calculation registry cannot find the requested calculation
Examples¶
try: ... api.calculate_metrics("data.zarr", calculations=["invalid_calc"]) ... except CalculationFailed as e: ... print(f"Calculation error: {e}")
APIConnectionError¶
Bases: GridFIAException
Raised when connection to FIA API fails.
This exception is raised when: - Network connection to FIA BIGMAP service fails - Request timeout occurs - Server returns error status codes (after retries) - Rate limiting prevents successful request
Examples¶
try: ... api.list_species() ... except APIConnectionError as e: ... print(f"API error: {e}")
InvalidLocationConfig¶
Bases: GridFIAException
Raised when location configuration is invalid.
This exception is raised when: - State name or abbreviation is not recognized - County is not found within the specified state - Bounding box coordinates are invalid - Configuration file is malformed or missing required fields
Examples¶
try: ... api.get_location_config(state="InvalidState") ... except InvalidLocationConfig as e: ... print(f"Location error: {e}")
DownloadError¶
Bases: GridFIAException
Raised when data download fails.
This exception is raised when: - Raster export from FIA service fails - Downloaded file is empty or corrupt - No files were successfully downloaded in a batch operation - Output directory cannot be created or written to
Examples¶
try: ... api.download_species(state="MT", species_codes=["0202"]) ... except DownloadError as e: ... print(f"Download error: {e}")
CircuitBreakerOpen¶
Bases: GridFIAException
Raised when circuit breaker is in OPEN state and requests are blocked.
This exception is raised when: - Too many consecutive failures have occurred - The circuit breaker is protecting against cascading failures - The recovery timeout has not yet elapsed
The circuit breaker will automatically transition to HALF_OPEN state after the recovery timeout to test if the service has recovered.
Examples¶
try: ... api.list_species() ... except CircuitBreakerOpen as e: ... print(f"Service unavailable: {e}") ... print(f"Retry after: {e.retry_after} seconds")
Error Recovery Patterns¶
Retry with Exponential Backoff¶
import time
from gridfia import GridFIA
from gridfia.exceptions import APIConnectionError, CircuitBreakerOpen
def download_with_retry(api, state, max_retries=3):
"""Download with exponential backoff on failure."""
for attempt in range(max_retries):
try:
return api.download_species(state=state)
except CircuitBreakerOpen as e:
# Wait for circuit breaker to reset
wait_time = e.retry_after or 60
print(f"Circuit breaker open, waiting {wait_time}s...")
time.sleep(wait_time)
except APIConnectionError as e:
# Exponential backoff
wait_time = 2 ** attempt
print(f"API error (attempt {attempt + 1}), retrying in {wait_time}s...")
time.sleep(wait_time)
raise RuntimeError(f"Failed after {max_retries} attempts")
Graceful Degradation¶
from gridfia import GridFIA
from gridfia.exceptions import CalculationFailed
api = GridFIA()
def calculate_all_metrics(zarr_path, calculations):
"""Calculate metrics with graceful degradation."""
results = []
failed = []
for calc in calculations:
try:
result = api.calculate_metrics(
zarr_path,
calculations=[calc]
)
results.extend(result)
except CalculationFailed as e:
print(f"Warning: {calc} failed - {e.message}")
failed.append(calc)
if failed:
print(f"Some calculations failed: {failed}")
return results
Validation Before Processing¶
from pathlib import Path
from gridfia import GridFIA
from gridfia.exceptions import InvalidZarrStructure, SpeciesNotFound
api = GridFIA()
def validate_and_process(zarr_path, species_codes):
"""Validate inputs before expensive processing."""
# Validate Zarr structure
try:
info = api.validate_zarr(zarr_path)
print(f"Valid Zarr: {info['shape']}")
except InvalidZarrStructure as e:
return {"error": "invalid_zarr", "details": e.details}
# Validate species codes exist in store
available = info.get("species_codes", [])
missing = [s for s in species_codes if s not in available]
if missing:
return {
"error": "missing_species",
"missing": missing,
"available": available
}
# Proceed with processing
return api.calculate_metrics(zarr_path)
Logging Errors¶
All exceptions include structured details for logging:
import logging
from gridfia import GridFIA, GridFIAException
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
api = GridFIA()
try:
api.download_species(state="InvalidState")
except GridFIAException as e:
logger.error(
"GridFIA operation failed",
extra={
"error_type": type(e).__name__,
"message": e.message,
"details": e.details
}
)
See Also¶
- GridFIA Class - Main API methods
- Configuration - Settings that affect error behavior