Exceptions
pydynox maps AWS SDK errors to Python exceptions. This makes error handling easier and more Pythonic.
Key features
- Clear exception hierarchy
- Helpful error messages
- Maps AWS errors to specific types
- Base exception for catch-all handling
Getting started
Exception hierarchy
All pydynox exceptions inherit from PydynoxException. You can catch specific errors or use the base class:
| Exception | When it happens |
|---|---|
PydynoxException |
Base exception for all pydynox errors |
ResourceNotFoundException |
Table does not exist |
ResourceInUseException |
Table already exists |
ValidationException |
Invalid input (bad key, wrong type, etc.) |
ConditionalCheckFailedException |
Condition expression returned false |
TransactionCanceledException |
Transaction failed |
ProvisionedThroughputExceededException |
Request rate too high |
AccessDeniedException |
IAM permission denied |
CredentialsException |
AWS credentials missing or invalid |
SerializationException |
Cannot convert data to/from DynamoDB format |
ConnectionException |
Cannot connect to DynamoDB |
EncryptionException |
KMS encryption/decryption failed |
S3AttributeException |
S3 upload/download failed |
ItemTooLargeException |
Item exceeds max_size limit (Python-only) |
Basic error handling
Import exceptions from pydynox.pydynox_core:
from pydynox import DynamoDBClient
from pydynox.pydynox_core import (
ConnectionException,
CredentialsException,
PydynoxException,
ResourceNotFoundException,
)
def safe_get_item():
client = DynamoDBClient()
try:
item = client.get_item("users", {"pk": "USER#123"})
return item
except ResourceNotFoundException:
print("Table does not exist")
except CredentialsException:
print("Check your AWS credentials")
except ConnectionException:
print("Cannot connect to DynamoDB")
except PydynoxException as e:
print(f"Something went wrong: {e}")
Condition check errors
When using conditional writes, catch ConditionalCheckFailedException:
from pydynox import DynamoDBClient
from pydynox.pydynox_core import ConditionalCheckFailedException
def update_if_exists():
client = DynamoDBClient()
try:
client.update_item(
"users",
{"pk": "USER#123"},
updates={"name": "John"},
condition_expression="attribute_exists(pk)",
)
print("Updated successfully")
except ConditionalCheckFailedException:
print("Item does not exist, cannot update")
Get the item that caused the failure
When a condition fails, you often need to see what's in DynamoDB. Instead of making an extra GET call, use return_values_on_condition_check_failure=True. The existing item is attached to the exception:
from pydynox import DynamoDBClient
from pydynox.pydynox_core import ConditionalCheckFailedException
def optimistic_lock_with_item_return():
"""Update with version check, get existing item on failure."""
client = DynamoDBClient()
# Try to update with version check
try:
client.update_item(
"users",
{"pk": "USER#123"},
updates={"name": "Alice", "version": 2},
condition_expression="#v = :expected",
expression_attribute_names={"#v": "version"},
expression_attribute_values={":expected": 1},
return_values_on_condition_check_failure=True,
)
print("Updated successfully")
except ConditionalCheckFailedException as e:
# No extra GET needed - item is on the exception
print(f"Version conflict! Current item: {e.item}")
print(f"Current version: {e.item['version']}")
def prevent_overwrite_with_item_return():
"""Create new item, get existing on conflict."""
client = DynamoDBClient()
try:
client.put_item(
"users",
{"pk": "USER#123", "name": "Bob", "email": "bob@example.com"},
condition_expression="attribute_not_exists(pk)",
return_values_on_condition_check_failure=True,
)
print("Created new user")
except ConditionalCheckFailedException as e:
# See what's already there without extra GET
print(f"User already exists: {e.item['name']}")
This works with put_item, update_item, and delete_item. The item attribute is None if you don't set the flag.
Advanced
Connection errors
ConnectionException happens when pydynox cannot reach DynamoDB. Common causes:
- DynamoDB Local is not running
- Wrong endpoint URL
- Network issues
- Firewall blocking the connection
from pydynox.pydynox_core import ConnectionException
try:
client = DynamoDBClient(endpoint_url="http://localhost:8000")
client.ping()
except ConnectionException:
print("Start DynamoDB Local first: docker run -p 8000:8000 amazon/dynamodb-local")
Credential errors
CredentialsException happens when AWS credentials are missing or invalid:
from pydynox.pydynox_core import CredentialsException
try:
client = DynamoDBClient()
client.ping()
except CredentialsException as e:
print(f"Fix your credentials: {e}")
Common causes: - No AWS credentials configured - Invalid access key or secret key - Expired session token - Wrong AWS profile name
Throttling errors
ProvisionedThroughputExceededException happens when you exceed your table's capacity:
from pydynox.pydynox_core import ProvisionedThroughputExceededException
import time
def save_with_retry(client, table, item, max_retries=3):
for attempt in range(max_retries):
try:
client.put_item(table, item)
return
except ProvisionedThroughputExceededException:
if attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff
time.sleep(wait_time)
else:
raise
Tip
Use the built-in rate limiting feature instead of manual retry logic. See the Rate limiting guide.
Transaction errors
TransactionCanceledException includes details about why the transaction failed:
from pydynox import Transaction
from pydynox.exceptions import TransactionCanceledException
try:
with Transaction() as tx:
tx.put("accounts", {"pk": "ACC#1", "balance": 100})
tx.update(
"accounts",
{"pk": "ACC#2"},
updates={"balance": 200},
condition_expression="attribute_exists(pk)",
)
except TransactionCanceledException as e:
print(f"Transaction failed: {e}")
# e.g., "Transaction was canceled: Condition check failed"
Encryption errors
EncryptionException happens when KMS encryption or decryption fails:
from pydynox.exceptions import EncryptionException
try:
user.save() # Has an EncryptedAttribute
except EncryptionException as e:
print(f"Encryption failed: {e}")
Common causes:
- KMS key not found (wrong key ID or alias)
- KMS key is disabled
- Missing IAM permissions for
kms:GenerateDataKeyorkms:Decrypt - Wrong encryption context on decrypt
- Invalid ciphertext (data corrupted)
Best practices
-
Catch specific exceptions first - Put specific handlers before the base
PydynoxException -
Log the full error - Exception messages include useful details from AWS
-
Use retry for throttling - Or better, use rate limiting to avoid throttling
-
Check credentials early - Call
client.ping()at startup to catch credential issues -
Handle connection errors gracefully - Especially in Lambda where cold starts can cause timeouts
Next steps
- IAM permissions - Required AWS permissions
- Rate limiting - Avoid throttling errors
- Observability - Logging and metrics