DynamoDB BatchGetItem with the AWS CLI

aws dynamodb batch-get-item fetches up to 100 items by primary key in one command. Two things separate it from query and scan on the command line: the keys are nested DynamoDB JSON you have to survive shell quoting, and the CLI will not drain UnprocessedKeys for you. The limits and the partial-result rules are in batch operations in DynamoDB.

Code

aws dynamodb batch-get-item \
  --request-items '{
    "Music": {
      "Keys": [
        {"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
        {"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "A Mis Abuelos"}},
        {"Artist": {"S": "Ella Fitzgerald"}, "SongTitle": {"S": "Misty"}}
      ]
    }
  }'

Abbreviated, the output maps each table to the items found plus any leftovers. The full verbatim run is further down the page:

{
    "Responses": {
        "Music": [
            {"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}, ...}
        ]
    },
    "UnprocessedKeys": {}
}

Explanation

  • The CLI has no pagination machinery for this command. aws dynamodb query help lists --starting-token, --max-items and --page-size; aws dynamodb batch-get-item help lists none of the three. UnprocessedKeys is not a pagination token and the CLI treats the call as one-shot, so draining it is your shell loop, not a flag.
  • The leftover map is already the input format. A non-empty UnprocessedKeys can be fed straight back as --request-items with no reshaping, which is what makes a while loop in bash tolerable. Sleep between attempts; an immediate re-run hits the same throttled partition.
  • ProjectionExpression and ConsistentRead go inside the per-table object, next to "Keys". Putting them at the top level of --request-items is the most common shape error here.
  • Keep the map in a file. --request-items file://keys.json sidesteps shell quoting entirely, and it is the only sane option past a handful of keys. It is also how you hit the 100-key ceiling without noticing.

What the command actually prints

The fence above, run verbatim against DynamoDB Local 3.3.0 with all three songs present (aws-cli/2.36.9):

{
    "Responses": {
        "Music": [
            {
                "Artist": {"S": "Arturo Sandoval"},
                "AlbumTitle": {"S": "Danzon"},
                "Year": {"N": "1994"},
                "SongTitle": {"S": "A Mis Abuelos"}
            },
            {
                "Artist": {"S": "Ella Fitzgerald"},
                "AlbumTitle": {"S": "Ella in Berlin"},
                "Year": {"N": "1960"},
                "SongTitle": {"S": "Misty"}
            },
            {
                "Artist": {"S": "Arturo Sandoval"},
                "AlbumTitle": {"S": "Danzon"},
                "Year": {"N": "1994"},
                "SongTitle": {"S": "Cubano Chant"}
            }
        ]
    },
    "UnprocessedKeys": {}
}

(Attribute maps folded onto one line each; everything else is as printed.) The command asked for Cubano Chant first and got it last. Nothing about the response is positional, so a jq expression that indexes .Responses.Music[0] is reading whichever item the service felt like returning first. Filter on the key attributes instead.

Two requests it rejects outright, printed to stderr with exit status 254:

aws: [ERROR]: An error occurred (ValidationException) when calling the BatchGetItem operation: Provided list of item keys contains duplicates
aws: [ERROR]: An error occurred (ValidationException) when calling the BatchGetItem operation: Too many items requested for the BatchGetItem call

The aws: [ERROR]: prefix is the CLI v2 wrapper; the text after it is the service's own message. A retry loop that treats any non-zero exit as throttling will spin forever on either of these, so branch on the message before you back off.

Hand-writing that nested JSON inside single quotes is where most of the errors come from. The DynamoDB Expression Builder assembles typed key maps and copies out a ready-to-run command, which at least removes the quoting from the list of suspects.

To read a set of keys back and see the items without the JSON round trip, download DynoTable.

References

Last verified 2026-07-28 against the official AWS documentation linked above.

Work with DynamoDB without the Console

A fast DynamoDB desktop client that runs the real SQL DynamoDB can’t — JOINs, GROUP BY, aggregates — with visual editing and an AI agent on your own Bedrock keys.

Free 30-day trial, no credit card — then the Free plan with no time limit.