DynamoDB returns ThrottlingException when your request rate exceeds the allowed throughput for your table, index, or account limits. This error occurs with both provisioned and on-demand capacity modes when you send too many requests too quickly.
The ThrottlingException error in DynamoDB indicates that your application is sending requests at a rate that exceeds the throughput limits configured for your table, global secondary index, or your AWS account. This error can occur in several scenarios: 1. **Provisioned capacity mode**: When your request rate exceeds the read or write capacity units (RCUs/WCUs) you've provisioned for a table or index 2. **On-demand mode**: When your request rate exceeds the account-level throughput limits for on-demand tables 3. **Hot partition/keys**: When requests are concentrated on a single partition key, exceeding the partition's throughput limits 4. **Control plane operations**: When performing too many administrative operations (CreateTable, UpdateTable, etc.) in quick succession DynamoDB uses throttling to maintain performance and fairness across all customers. When throttled, requests are rejected with HTTP status code 400 and the ThrottlingException error.
AWS SDKs automatically implement exponential backoff for throttling errors, but you should verify your configuration:
// AWS SDK v3 for JavaScript automatically handles retries
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({
region: 'us-east-1',
maxAttempts: 10, // Default is 3, increase for high-throughput applications
});
// For custom retry logic:
const delay = (retryCount) => {
const baseDelay = 50; // 50ms
const maxDelay = 5000; // 5 seconds
const delay = Math.min(maxDelay, baseDelay * Math.pow(2, retryCount));
const jitter = delay * 0.1 * Math.random(); // Add 10% jitter
return delay + jitter;
};Key points:
- AWS SDKs handle retries automatically for throttling errors
- Increase maxAttempts for high-throughput applications
- Add jitter to prevent synchronized retry storms across multiple clients
Check your current provisioned capacity and adjust based on actual usage:
# Check current provisioned capacity
aws dynamodb describe-table --table-name YourTableName
# Update provisioned capacity
aws dynamodb update-table \
--table-name YourTableName \
--provisioned-throughput \
'ReadCapacityUnits=100,WriteCapacityUnits=50'
# For global secondary indexes
aws dynamodb update-table \
--table-name YourTableName \
--global-secondary-index-updates \
'[{
"Update": {
"IndexName": "YourIndexName",
"ProvisionedThroughput": {
"ReadCapacityUnits": 50,
"WriteCapacityUnits": 25
}
}
}]'Best practices:
- Monitor CloudWatch metrics: ConsumedReadCapacityUnits, ConsumedWriteCapacityUnits, ThrottledRequests
- Set GSI write capacity ≥ base table write capacity
- Use auto-scaling with target utilization around 70%
Configure auto-scaling to automatically adjust capacity based on demand:
# Register scalable target
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/YourTableName" \
--scalable-dimension "dynamodb:table:ReadCapacityUnits" \
--min-capacity 5 \
--max-capacity 1000
# Create scaling policy for read capacity
aws application-autoscaling put-scaling-policy \
--service-namespace dynamodb \
--resource-id "table/YourTableName" \
--scalable-dimension "dynamodb:table:ReadCapacityUnits" \
--policy-name "ReadScalingPolicy" \
--policy-type "TargetTrackingScaling" \
--target-tracking-scaling-policy-configuration \
'{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "DynamoDBReadCapacityUtilization"
},
"ScaleOutCooldown": 60,
"ScaleInCooldown": 300
}'Configuration tips:
- Set TargetValue to 70% for balanced performance and cost
- Use longer ScaleInCooldown (300 seconds) than ScaleOutCooldown (60 seconds) to prevent rapid scale-in
- Monitor scaling activities in CloudWatch
If requests are concentrated on specific partition keys, implement strategies to distribute load:
// Example: Add random suffix to partition key
function getPartitionKey(userId) {
const suffix = Math.floor(Math.random() * 10); // 0-9
return `user-${userId}-${suffix}`;
}
// Example: Use composite key with timestamp
function getTimeBasedKey(entityId) {
const hour = new Date().getHours();
return `${entityId}-${hour}`;
}
// Example: Use write sharding for high-velocity data
function getShardedKey(streamId) {
const shardId = streamId % 100; // Distribute across 100 shards
return `stream-${shardId}`;
}Strategies:
- Add random suffixes or prefixes to partition keys
- Use composite keys with timestamps for time-series data
- Implement write sharding for high-velocity streams
- Consider using DynamoDB Accelerator (DAX) for read-heavy hot keys
Handle partial failures in batch operations and implement proper retry logic:
// Process BatchWriteItem with retry logic
async function batchWriteWithRetry(items, tableName) {
let unprocessedItems = { [tableName]: items };
while (Object.keys(unprocessedItems[tableName] || {}).length > 0) {
const response = await dynamodb.batchWriteItem({
RequestItems: unprocessedItems
}).promise();
unprocessedItems = response.UnprocessedItems || {};
if (Object.keys(unprocessedItems).length > 0) {
// Exponential backoff with jitter
const delay = Math.min(5000, 50 * Math.pow(2, retryCount));
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// For transactions, use ClientRequestToken for idempotency
const transactionParams = {
TransactItems: [
{ Put: { TableName: 'Table1', Item: item1 } },
{ Update: { TableName: 'Table2', Key: key2, UpdateExpression: 'SET #count = #count + :inc' } }
],
ClientRequestToken: 'unique-transaction-id-' + Date.now()
};Best practices:
- Always process UnprocessedItems from batch operations
- Use ClientRequestToken for transaction idempotency
- Limit batch sizes to 25 items to avoid size limits
For unpredictable workloads, switch to on-demand capacity mode:
# Switch table to on-demand mode
aws dynamodb update-table \
--table-name YourTableName \
--billing-mode PAY_PER_REQUEST
# Check current billing mode
aws dynamodb describe-table --table-name YourTableName \
--query 'Table.BillingModeSummary.BillingMode'When to use on-demand:
- Unpredictable or spiky workloads
- New applications with unknown traffic patterns
- Development and testing environments
- Applications with low to moderate traffic
Limitations:
- Account-level throughput limits still apply
- Can be more expensive for steady, predictable workloads
- Switching back to provisioned mode requires 24-hour wait
## Throttling Diagnostics and Monitoring
### CloudWatch Metrics to Monitor:
- ThrottledRequests: Count of throttled read/write requests
- ConsumedReadCapacityUnits / ConsumedWriteCapacityUnits: Actual capacity used
- ProvisionedReadCapacityUnits / ProvisionedWriteCapacityUnits: Configured capacity
- UserErrors: Client-side errors including throttling
- SystemErrors: Server-side errors
### ThrottlingReason Analysis:
DynamoDB returns detailed throttling reasons in error responses:
- TableReadProvisionedThroughputExceeded: Table read capacity exceeded
- IndexWriteProvisionedThroughputExceeded: GSI write capacity exceeded
- TableReadKeyRangeThroughputExceeded: Hot partition key read throttling
- IndexWriteMaxOnDemandThroughputExceeded: On-demand index write limit
- TableWriteAccountLimitExceeded: Account-level write limit
### Partition Throughput Limits:
Each partition in DynamoDB has limits:
- Provisioned mode: 3000 RCUs and 1000 WCUs per partition
- On-demand mode: Higher limits but still subject to partition constraints
### DynamoDB Streams Throttling:
- Maximum 2 simultaneous readers per shard
- Use Kinesis Data Streams for higher fanout needs
- Monitor ReadThrottleEvents metric
### Best Practices for High-Throughput Applications:
1. Implement circuit breakers to fail fast during sustained throttling
2. Use connection pooling to limit concurrent requests
3. Implement request queuing with backpressure signaling
4. Consider DynamoDB Accelerator (DAX) for read-heavy workloads
5. Use AWS X-Ray to trace throttling patterns in distributed systems
### When to Contact AWS Support:
- Consistently hitting account-level throughput limits
- Need quota increases for on-demand tables
- Suspected partition imbalance issues
- Production-critical applications requiring dedicated support
ImportConflictException: There was a conflict when attempting to import to the table
How to fix 'ImportConflictException: There was a conflict when attempting to import to the table' in DynamoDB
ResourceNotFoundException: Requested resource not found
How to fix "ResourceNotFoundException: Requested resource not found" in DynamoDB
TrimmedDataAccessException: The requested data has been trimmed
How to fix "TrimmedDataAccessException: The requested data has been trimmed" in DynamoDB Streams
GlobalTableNotFoundException: Global Table not found
How to fix "GlobalTableNotFoundException: Global Table not found" in DynamoDB
InvalidExportTimeException: The specified ExportTime is outside of the point in time recovery window
How to fix "InvalidExportTimeException: The specified ExportTime is outside of the point in time recovery window" in DynamoDB