SQS messages can’t be larger than 256KB, and when you hit that limit, your producer will start getting errors like MessageTooLarge.
This isn’t just an arbitrary limit; it’s a fundamental design choice in SQS. It ensures that messages are small enough to be processed quickly by consumers and that the queue itself remains responsive. When a message exceeds this, SQS simply refuses to accept it, preventing potential bottlenecks and ensuring reliable delivery for smaller messages.
Here’s how to diagnose and fix it, beyond the obvious:
1. The Payload is Actually Big
This is the most straightforward cause. You’re trying to put more than 256KB of data directly into an SQS message.
Diagnosis:
Before sending, check the size of your message payload. If you’re using a library, many have a getMessageSize() or similar method. If not, a simple Python script can do it:
import json
payload = {
"key1": "value1" * 50000, # Simulate a large string
"key2": [1, 2, 3] * 10000
}
message_body = json.dumps(payload)
print(f"Message size: {len(message_body.encode('utf-8'))} bytes")
Fix:
The SQS message body is limited to 256KB (262,144 bytes). Reduce the size of your data. This might involve compressing data before sending (though the compression itself adds overhead), or, more commonly, serializing your data more efficiently. For instance, using msgpack instead of json can often halve the size.
import msgpack
import json
payload = {
"key1": "value1" * 50000,
"key2": [1, 2, 3] * 10000
}
# Using JSON
message_body_json = json.dumps(payload)
print(f"JSON size: {len(message_body_json.encode('utf-8'))} bytes")
# Using MessagePack
packed_payload = msgpack.packb(payload, use_bin_type=True)
print(f"MsgPack size: {len(packed_payload)} bytes")
If even MessagePack is too large, you’re likely looking at the S3 workaround.
2. Large Attributes, Not Just Body
SQS message attributes also have a size limit. The total size of message attributes (name and value) is limited to 256KB, in addition to the 256KB limit for the message body. This is a common oversight; people focus on the body and forget attributes can contribute significantly.
Diagnosis:
When sending a message, iterate through your attributes and sum their sizes. The AWS SDKs often provide a way to inspect this. For example, in Python’s boto3:
import boto3
sqs = boto3.client('sqs')
queue_url = 'YOUR_QUEUE_URL'
message_attributes = {
'LargeAttribute': {
'StringValue': 'some_very_long_string' * 20000,
'DataType': 'String'
},
'AnotherAttribute': {
'StringValue': 'another_long_string' * 15000,
'DataType': 'String'
}
}
# Manually calculate attribute size (this is an approximation, SDKs might have better tools)
attribute_size = 0
for name, attribute in message_attributes.items():
attribute_size += len(name.encode('utf-8'))
if attribute['DataType'] == 'String':
attribute_size += len(attribute['StringValue'].encode('utf-8'))
# Handle other data types if necessary (Binary, Number)
print(f"Approximate attribute size: {attribute_size} bytes")
try:
sqs.send_message(
QueueUrl=queue_url,
MessageBody='Hello',
MessageAttributes=message_attributes
)
except sqs.exceptions.MessageSizeExceeded as e:
print(f"Error sending message: {e}")
Fix: Move large attribute values into the message body or, preferably, into S3. If an attribute is crucial for filtering and must remain an attribute, you might need to serialize its content more efficiently or truncate it and have the consumer fetch the full data elsewhere.
3. Base64 Encoding Overhead
If you’re sending binary data, you might be encoding it to Base64 before putting it into the SQS message body or as a String attribute. Base64 encoding increases the data size by approximately 33%.
Diagnosis: Compare the raw binary size of your data with its Base64 encoded string representation.
import base64
binary_data = b'\xff\xd8\xff\xe0\x00\x10JFIF...' # Your binary data here
base64_encoded_data = base64.b64encode(binary_data).decode('utf-8')
print(f"Raw binary size: {len(binary_data)} bytes")
print(f"Base64 encoded size: {len(base64_encoded_data.encode('utf-8'))} bytes")
If len(base64_encoded_data.encode('utf-8')) is significantly larger than your original binary data and pushing you over the 256KB limit, this is your culprit.
Fix: If you’re sending binary data and it’s causing size issues, consider storing it in S3 and sending only the S3 object key as the SQS message body or an attribute.
4. The S3 Workaround: Storing Large Payloads
For messages that legitimately need to be larger than 256KB, the standard AWS pattern is to use Amazon S3 as a buffer.
Diagnosis: You’ve exhausted other options for reducing message size, and your data consistently exceeds 256KB.
Fix:
-
Producer:
- Upload your large message payload to an S3 bucket.
- Generate a pre-signed URL for the S3 object or store the object key and bucket name.
- Send an SQS message containing only the S3 object’s key/bucket or the pre-signed URL.
import boto3 import uuid s3 = boto3.client('s3') sqs = boto3.client('sqs') queue_url = 'YOUR_QUEUE_URL' bucket_name = 'your-large-message-bucket' object_key = f'messages/{uuid.uuid4()}.json' # Unique key for each message large_payload = { "data": "this is a very large payload..." * 10000 } # Upload to S3 s3.put_object(Bucket=bucket_name, Key=object_key, Body=json.dumps(large_payload)) # Send SQS message with S3 object key message_body = object_key # Or a JSON structure with bucket and key sqs.send_message( QueueUrl=queue_url, MessageBody=message_body ) print(f"Sent SQS message with S3 object key: {object_key}") -
Consumer:
- Receive the SQS message.
- Extract the S3 object key (and bucket name) from the message body.
- Download the object from S3.
- Process the downloaded content.
import boto3 import json s3 = boto3.client('s3') sqs = boto3.client('sqs') queue_url = 'YOUR_QUEUE_URL' bucket_name = 'your-large-message-bucket' # If not included in message body response = sqs.receive_message( QueueUrl=queue_url, MaxNumberOfMessages=1, WaitTimeSeconds=5 # Long polling ) if 'Messages' in response: message = response['Messages'][0] s3_object_key = message['Body'] # Assuming message body is just the key # Download from S3 s3_object = s3.get_object(Bucket=bucket_name, Key=s3_object_key) message_content = json.loads(s3_object['Body'].read().decode('utf-8')) print(f"Processing message from S3 object: {s3_object_key}") # Process message_content... # Delete the SQS message after successful processing sqs.delete_message( QueueUrl=queue_url, ReceiptHandle=message['ReceiptHandle'] )
This pattern decouples the message delivery mechanism (SQS) from the data storage (S3), effectively bypassing the SQS size limit.
5. Message Attributes vs. Body Content
Sometimes, the combination of a large message body and large attributes can push you over. It’s not just one or the other.
Diagnosis: Use the diagnostic methods from points 1 and 2. If the body is near 256KB and the attributes are also substantial, their combined size might exceed the limit.
Fix: Prioritize what needs to be in the message body vs. attributes. If filtering is critical, keep only essential filtering data in attributes. Move the bulk of the payload to S3 as described in point 4.
6. SDK or Client-Side Issues
Rarely, a bug in the AWS SDK you’re using, or a misconfiguration in your client-side code, might lead to messages being erroneously reported as too large or incorrectly sized.
Diagnosis:
- Update SDK: Ensure you’re using the latest version of your AWS SDK. Check the SDK’s release notes for any known issues related to SQS message sizing.
- Manual Check: As shown in point 1, manually calculate the size of your serialized message before passing it to the SDK’s
send_messagefunction. If your manual calculation is below 256KB but the SDK still errors, it might indicate an SDK issue or an unexpected serialization step within the SDK. - Test with Minimal Payload: Try sending a very simple, small message (e.g.,
{"test": "1"}) to the same queue. If that works, the issue is almost certainly with your specific message content’s size.
Fix: If an SDK bug is suspected, report it to AWS and consider a temporary workaround. Otherwise, the fix is to ensure your message serialization is correct and within limits before calling the SDK.
The next error you’ll likely encounter if you fix message size is related to the complexity of your consumer logic, or perhaps a deadlock if multiple consumers are trying to process the same large data from S3.