DynamoDB PutItem with the AWS CLI
aws dynamodb put-item writes a whole item and replaces any existing item with the same primary key (item-based actions covers how that differs from update-item). The CLI's own contribution to the problem is the shell: --item takes DynamoDB JSON as a single quoted argument, and every attribute value is typed.
Code
aws dynamodb put-item \
--table-name 'Music' \
--item '{"Artist":{"S":"Arturo Sandoval"},"SongTitle":{"S":"Cubano Chant"},"AlbumTitle":{"S":"Danzon"},"Year":{"N":"1994"},"Awards":{"N":"0"}}' \
--condition-expression 'attribute_not_exists(#cond0) AND attribute_not_exists(#cond1)' \
--expression-attribute-names '{"#cond0":"Artist","#cond1":"SongTitle"}'On success the command prints nothing and exits 0. If the item already exists, the condition fails:
An error occurred (ConditionalCheckFailedException) when calling the PutItem operation:
The conditional request failedExplanation
Silence and exit 0 are the only success signal. put-item prints no JSON unless you ask for --return-values, so a script that greps stdout for confirmation will never fire. Check $?. Running the command above twice on aws-cli/2.36.9 gave:
first run: (no output) exit 0
second run: aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the PutItem operation: The conditional request failed
exit 254254 is "the service said no", not "the CLI broke". The AWS CLI reserves 252/253 for its own syntax and config problems and 255 for everything else, so a ConditionalCheckFailedException, a ValidationException and a throttle all land on the same 254. If your script needs to tell an expected condition failure from a real fault, parse the error name, not the exit code. Note also that 2.36.9 prefixes the message with aws: [ERROR]: , which older builds did not; a regex anchored at ^An error occurred will silently stop matching after a CLI upgrade.
A failed conditional write still costs you. The condition is evaluated by the service after it has located the item, and AWS is explicit that "if the expression evaluates to false, DynamoDB still consumes write capacity units from the table" (fetched 2026-07-28). A retry loop around a create-only put bills every attempt. For scale, --return-consumed-capacity TOTAL on a successful put of a ~15 KB item reported "CapacityUnits": 15. Writes round to 1 KB, not the 4 KB reads use.
--return-values-on-condition-check-failure works, but the CLI hides the answer. This is the flag that tells you which item blocked the write, without a second read. Add it and 2.36.9 prints:
aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the PutItem operation: The conditional request failed
Additional error details:
Item: <complex value>
Use "--cli-error-format json" or another error format to see the full details.The item is in the response the whole time; the default error formatter refuses to render it. Add --cli-error-format json to get it. (--return-values ALL_OLD is the unconditional cousin and only fires on success; ReturnValues covers the five options.)
Quoting is the other half of the job. The --item argument is one shell token containing JSON containing quoted numbers ({"N": "1994"}, never 1994). Anything with an apostrophe in it, and any item past a few hundred bytes, is easier as --item file://song.json. --cli-input-json file://request.json goes further and takes the entire request, condition expression included, which is also the form you can diff in review.
The aliases are not optional decoration. #cond0/#cond1 resolve to Artist/SongTitle through --expression-attribute-names. Writing the names inline works right up until one of them collides with a reserved word, at which point the command fails on a name you did not change.
Do it visually
Hand-typing typed JSON for --item is where most of these commands die. The free DynamoDB JSON converter takes ordinary JSON and returns the {"S": …} / {"N": …} form the flag wants, ready to save as the file:// payload.
To add and edit items against your own tables — a form per attribute, type pickers, copy the result back out as a CLI command — download DynoTable.
Related guides
- DynamoDB condition expressions —
attribute_not_exists, optimistic locking, and more. - DynamoDB data types — how each attribute type is written in DynamoDB JSON.
- DynamoDB ConditionalCheckFailedException — what the create-only condition throws when the item already exists.
- DynamoDB ValidationException — the catch-all for a malformed item or expression.
References
- PutItem — Amazon DynamoDB API Reference
- put-item — AWS CLI Command Reference
- Understanding return codes — AWS CLI User Guide
- Condition expressions — Amazon DynamoDB Developer Guide
- Working with items and attributes — Amazon DynamoDB Developer Guide
Reproduced 2026-07-28 with aws-cli/2.36.9 against DynamoDB Local (amazon/dynamodb-local) on port 9000. The exit codes, the error text and the capacity reading are captured output. The failed-write capacity claim is quoted from the AWS docs rather than measured: DynamoDB Local returns no ConsumedCapacity on the condition-failure path.