- Return-tuple errors —
(result, err)for operations with expected failure paths (e.g. upload/download). Checkerr is not Nonebefore usingresult. - Raised exceptions — for programming errors, invalid input, and unrecoverable failures.
StorageError and carries structured context you can inspect for automated recovery.
Exception hierarchy
exceptions:
Error structure
EveryStorageError carries four optional attributes:
| Attribute | Type | Description |
|---|---|---|
message | str | Human-readable description |
error_code | str | None | Machine-readable code (e.g. "NETWORK_ERROR", "TIMEOUT") |
context | dict | Structured metadata (operation name, URL, tx hash, etc.) |
cause | Exception | None | The original exception that triggered this one |
Return-tuple pattern
Indexer and Uploader/Downloader methods return (result, err) tuples. Always branch on err:
indexer.download() returns a single err (or None) rather than a tuple:
Classifying retryable errors
RetryableError and its subclasses signal transient failures you can safely retry. The is_retryable() helper handles the classification:
RetryableError tracks retry_count and max_retries if you want to bound retry loops:
ErrorContext for multi-step operations
For operations that may accumulate multiple failures (e.g. batch uploads),ErrorContext collects them:
ctx.errors, and optionally raises a combined StorageError when you call raise_if_errors().
Decorator form
Wrap a function with the same semantics usingwrap_with_context:
Converting low-level exceptions
The error-handler module provides helpers that wrap generic exceptions into the SDK’s structured types:error_code and attaches relevant context fields.
Validate input early
validate_input raises InvalidInputError for parameter problems — use it at API boundaries:
Safe calling
For best-effort operations where you want to catch everything and continue:safe_call runs the callable and returns the default value on any exception, logging the error without propagating it.
When to catch vs re-raise
| Situation | Action |
|---|---|
is_retryable(err) is true | Retry with backoff |
InvalidInputError | Fix the input — don’t retry |
InsufficientReplicasError | Increase expected_replica or wait for more nodes |
MerkleTreeError | Bug or corrupted input — report with reproducer |
TransactionError with tx_hash | Inspect on-chain; may need manual recovery |
NodeConnectionError to one node | Try a different node from indexer.select_nodes() |
Unknown / non-StorageError exception | Bubble up — likely a programming error |
Example: retry with backoff
retry_opts directly to indexer.upload() and let the SDK handle retries internally.
Next steps
Upload & download
The core file flow that produces most SDK errors.
Large files
Multi-fragment upload patterns with independent retry granularity.