How to Persist Orders to DynamoDB From a Python App on AWS EC2

A Flask orders service on AWS returns 500 on every POST and nothing lands in DynamoDB. The cause is almost always a partition-key mismatch: the boto3 put_item item uses a field like id while the table was created with order_id as the HASH key, so DynamoDB rejects the write with ValidationException. Rename the key to match the table schema and writes start persisting.

Backend Engineerpythonflaskaws

Why put_item returns 500 with a ValidationException

A DynamoDB table is schemaless for its non-key attributes, but the partition key (and sort key, if the table has one) is not optional. Every put_item must include the partition key attribute, named exactly as it was declared when the table was created. Miss it and DynamoDB rejects the write:

ValidationException: One or more parameter values were invalid:
Missing the key order_id in the item

In a typical broken orders service the table was created with order_id as the partition key, but the boto3 write sends id instead. Because the Flask handler wraps the write in a try/except that returns 500, the client only sees a generic error and the table stays empty. Confirm the real table schema before touching code:

aws dynamodb describe-table --table-name Orders \
    --query 'Table.KeySchema'

That prints [{"AttributeName": "order_id", "KeyType": "HASH"}] - the write has to supply order_id, not id.

The fix: match the item key to the table key

The bug lives in the put_item call. The item dict names the partition key id, which the table does not know about:

# BEFORE - write fails with ValidationException, handler returns 500
table.put_item(Item={
    "id": body["id"],
    "customer": body["customer"],
    "amount": body["amount"],
})

Rename the field to the declared partition key. Nothing else changes - the other attributes are free-form:

# AFTER - order_id matches the table's HASH key, write succeeds
table.put_item(Item={
    "order_id": body["id"],
    "customer": body["customer"],
    "amount": body["amount"],
})

Restart the service and re-send the order. A correct write returns 201:

pkill -f order_writer.py; python3 order_writer.py &

curl -sX POST http://localhost:8000/orders \
    -H 'Content-Type: application/json' \
    -d '{"id":"o-1","customer":"alice","amount":42}'
# {"created":"o-1"}  with HTTP 201

Verify the item actually landed in the table instead of trusting the status code:

aws dynamodb scan --table-name Orders --select COUNT --query 'Count'

Keep the writer and the table in sync

This class of bug is silent whenever the exception is swallowed, so the goal is to make a key mismatch impossible rather than to catch it after the fact.

The same pattern applies whether the app runs on AWS EC2, in a container, or on Lambda: the partition key attribute must be present in every write, spelled the same way the table was created.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

Why does my DynamoDB put_item fail with ValidationException Missing the key?

The item you passed does not include the table's partition key attribute, or spells it differently than the table was created with. DynamoDB requires the partition key (and sort key, if any) in every write, named exactly as declared in the KeySchema. Run aws dynamodb describe-table to see the real key name and match it.

How do I find a DynamoDB table's partition key name?

Run aws dynamodb describe-table --table-name Orders --query 'Table.KeySchema'. It returns the attribute names and their KeyType (HASH for the partition key, RANGE for the sort key). Your boto3 item must use those exact attribute names.

Does DynamoDB require a schema for every attribute?

No. DynamoDB is schemaless for non-key attributes, so any write can add new fields freely. The only required attributes are the partition key and the optional sort key, which must appear in every item exactly as named at table-create time.

How do I persist data to DynamoDB from a Python app on AWS EC2?

Create a boto3 resource for dynamodb, get the table, and call table.put_item with an item dict that includes the table's partition key. On an EC2 instance boto3 picks up credentials from the instance role automatically, so you do not hardcode keys - just make sure the item's key attribute names match the table.

Keep learning

Drain an AWS SQS Queue Without DuplicatesBackend projectGenerate an S3 Presigned Upload URLBackend projectLaunch an EC2 Instance With TerraformBackend projectBackend roadmapStep by step to hiredBackend interview questionsSTAR answersAll Backend projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →