tif1 uses a structured exception hierarchy to help you handle errors gracefully. All exceptions inherit from TIF1Error and include contextual information.
Exception Hierarchy
TIF1Error (base)
├── DataNotFoundError
│ ├── DriverNotFoundError
│ └── LapNotFoundError
├── NetworkError
├── InvalidDataError
├── CacheError
└── SessionNotLoadedError
Base Exception
TIF1Error
Base exception for all tif1 errors. All exceptions accept **context kwargs for structured error information.
class TIF1Error(Exception):
def __init__(self, message: str, **context: Any) -> None
Attributes:
message: Error message string
context: Dictionary of contextual information
Example:
try:
session = tif1.get_session(2025, "Invalid GP", "Race")
except tif1.TIF1Error as e:
print(f"Error: {e.message}")
print(f"Context: {e.context}")
Data Errors
DataNotFoundError
Raised when requested data is not available in the CDN.
class DataNotFoundError(TIF1Error):
def __init__(
self,
year: int | None = None,
event: str | None = None,
session: str | None = None,
**context: Any
) -> None
Context:
year: The requested year
event: The requested event name
session: The requested session name
Example:
try:
session = tif1.get_session(2030, "Future GP", "Race")
except tif1.DataNotFoundError as e:
print(f"Data not found: {e.context}")
# {'year': 2030, 'event': 'Future GP', 'session': 'Race'}
DriverNotFoundError
Raised when a driver code is not found in the session.
class DriverNotFoundError(DataNotFoundError):
def __init__(self, driver: str, **context: Any) -> None
Context:
driver: The requested driver code
Example:
try:
driver = session.get_driver("XXX")
except tif1.DriverNotFoundError as e:
print(f"Driver '{e.context['driver']}' not found")
print(f"Available: {session.drivers}")
``` ### `LapNotFoundError`
Raised when a lap number is not found for a driver.
```python
class LapNotFoundError(DataNotFoundError):
def __init__(
self,
lap_number: int | None = None,
driver: str | None = None,
**context: Any
) -> None
Context:
lap_number: The requested lap number
driver: The driver code
Example:
try:
lap = driver.get_lap(999)
except tif1.LapNotFoundError as e:
print(f"Lap {e.context['lap_number']} not found for {e.context['driver']}")
Network Errors
NetworkError
Raised when network requests fail after all retries and CDN fallbacks are exhausted.
class NetworkError(TIF1Error):
def __init__(
self,
url: str | None = None,
status_code: int | None = None,
**context: Any
) -> None
Context:
url: The URL that failed
status_code: HTTP status code (if available)
Example:
try:
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
laps = session.laps
except tif1.NetworkError as e:
print(f"Network error: {e.message}")
print(f"URL: {e.context.get('url')}")
print(f"Status: {e.context.get('status_code')}")
Data validation errors
InvalidDataError
Raised when fetched data is invalid, corrupted, or fails validation.
class InvalidDataError(TIF1Error):
def __init__(self, reason: str | None = None, **context: Any) -> None
Context:
reason: Description of why the data is invalid
Example:
try:
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
laps = session.laps
except tif1.InvalidDataError as e:
print(f"Invalid data: {e.context.get('reason')}")
Cache Errors
CacheError
Raised when cache operations fail (e.g., SQLite errors, disk full).
class CacheError(TIF1Error)
Example:
try:
cache = tif1.get_cache()
cache.clear()
except tif1.CacheError as e:
print(f"Cache error: {e.message}")
``` ---
## Session state errors
### `SessionNotLoadedError`
Raised when accessing session data before it has been loaded.
```python
class SessionNotLoadedError(TIF1Error):
def __init__(self, attribute: str | None = None) -> None
Context:
attribute: The attribute that was accessed
Example:
try:
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
# Accessing data without loading first (if lazy loading is disabled)
drivers = session._drivers # Internal attribute
except tif1.SessionNotLoadedError as e:
print(f"Session not loaded. Call session.load() first.")
Error handling patterns
Basic Try-Catch
import tif1
try:
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
laps = session.laps
fastest = session.get_fastest_laps()
except tif1.DataNotFoundError as e:
print(f"Data not found: {e.message}")
except tif1.NetworkError as e:
print(f"Network error: {e.message}")
except tif1.TIF1Error as e:
print(f"General error: {e.message}")
Specific error handling
import tif1
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
# Handle driver not found
try:
driver = session.get_driver("XXX")
except tif1.DriverNotFoundError:
print(f"Driver not found. Available: {session.drivers}")
driver = session.get_driver(session.drivers[0])
# Handle lap not found
try:
lap = driver.get_lap(999)
except tif1.LapNotFoundError:
print("Lap not found. Using fastest lap instead.")
lap_df = driver.get_fastest_lap()
Retry with Fallback
import tif1
import time
def load_session_with_retry(year, gp, session_name, max_retries=3):
for attempt in range(max_retries):
try:
session = tif1.get_session(year, gp, session_name)
laps = session.laps
return session
except tif1.NetworkError as e:
if attempt < max_retries - 1:
print(f"Network error, retrying... ({attempt + 1}/{max_retries})")
time.sleep(2 ** attempt) # Exponential backoff
else:
print("Max retries exceeded")
raise
except tif1.DataNotFoundError:
print("Data not found, cannot retry")
raise
session = load_session_with_retry(2021, "Belgian Grand Prix", "Race")
Context-aware error handling
import tif1
try:
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
driver = session.get_driver("VER")
lap = driver.get_lap(1)
tel = lap.telemetry
except tif1.TIF1Error as e:
# Access structured context
print(f"Error: {e.message}")
if 'year' in e.context:
print(f"Year: {e.context['year']}")
if 'driver' in e.context:
print(f"Driver: {e.context['driver']}")
if 'lap_number' in e.context:
print(f"Lap: {e.context['lap_number']}")
# Log full context for debugging
print(f"Full context: {e.context}")
Graceful Degradation
import tif1
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
# Try to get telemetry, fall back to lap data only
drivers_data = {}
for driver_code in session.drivers:
try:
driver = session.get_driver(driver_code)
fastest_tel = driver.get_fastest_lap_tel()
drivers_data[driver_code] = {
'has_telemetry': True,
'telemetry': fastest_tel
}
except tif1.TIF1Error as e:
# Fall back to lap data only
fastest_lap = driver.get_fastest_lap()
drivers_data[driver_code] = {
'has_telemetry': False,
'lap_data': fastest_lap
}
print(f"Warning: No telemetry for {driver_code}: {e.message}")
Best Practices
-
Catch specific exceptions first: Handle
DriverNotFoundError before DataNotFoundError, and DataNotFoundError before TIF1Error.
-
Use context information: All exceptions include structured context via the
context attribute.
-
Don’t swallow errors silently: Always log or handle errors appropriately.
-
Implement retries for network errors: Network errors are often transient.
-
Validate user input early: Check driver codes and lap numbers before making expensive API calls.
-
Use try-finally for cleanup: Ensure resources are cleaned up even if errors occur.
cache = tif1.get_cache()
try:
# ... operations ...
pass
finally:
cache.close()
``` 7. **Log context for debugging**: The `context` dict contains valuable debugging information.
```python
import logging
try:
session = tif1.get_session(2021, "Belgian Grand Prix", "Race")
except tif1.TIF1Error as e:
logging.error(f"Error: {e.message}", extra=e.context)
Last modified on March 5, 2026