The provided starting key is invalid
TL;DR — Your ExclusiveStartKey doesn't match the key schema of what you're paginating. It must contain exactly the key attributes DynamoDB returned in LastEvaluatedKey — the full primary key, plus the index key when you're querying a GSI/LSI — with the same names and types. Pass LastEvaluatedKey back verbatim; hand-assembling it is how this breaks.
What it means
ValidationException: The provided starting key is invalidValidationException: Exclusive Start Key must have same size as table's key schemaExclusiveStartKey tells a Query/Scan where to resume. DynamoDB validates it against the key schema of the table — or, for an index query, the combined index-plus-table key that LastEvaluatedKey carries. Missing attributes, extra attributes, wrong names, or wrong types all fail before any data is read.
Why it happens
- Hand-building the key with only the partition key — a composite-key table needs partition and sort key in the starting key.
- Paginating an index with just the table key —
LastEvaluatedKeyon a GSI/LSI query contains both the index key attributes and the table's primary key; all of them must come back. - Type or name drift — the key was serialized (JSON, URL param, cache) and came back with
"42"whereLastEvaluatedKeyhad a number, or with a renamed field. - Reusing a key across queries — a
LastEvaluatedKeyfrom one table/index passed to a query against another, or to the same query after the key schema assumption changed. - A wrapper injecting defaults — an ODM that fills in attributes it thinks belong in the key can pad the starting key past the schema size.
How to fix it
Round-trip
LastEvaluatedKeyuntouched:let ExclusiveStartKey; do { const page = await docClient.send( new QueryCommand({ TableName, KeyConditionExpression, ExpressionAttributeValues, ExclusiveStartKey }) ); items.push(...(page.Items ?? [])); ExclusiveStartKey = page.LastEvaluatedKey; // verbatim — no rebuild } while (ExclusiveStartKey);Serialize it losslessly if it crosses a request boundary — when the pagination cursor goes to a browser and back, encode the whole
LastEvaluatedKeyobject (e.g. base64 of its JSON) instead of reconstructing it from item fields, and keep number types numbers.Include every key attribute for index pagination — index partition/sort key and table partition/sort key, exactly as returned.
Don't fabricate a starting point — DynamoDB pagination has no offset; if you need "start near X", express it in the
KeyConditionExpression(sk > :x) rather than a hand-madeExclusiveStartKey.
Inspecting what LastEvaluatedKey actually contains for your table or index takes the guesswork out — the DynoTable desktop app pages through queries and shows the raw cursor, and the DynamoDB Expression Builder composes the query request around it.
Related errors
- The provided key element does not match the schema — the same schema mismatch on a
GetItem/write key. - Query key condition not supported
- Code example: Get all items in Node.js · in Python (boto3) — the LastEvaluatedKey pagination loop done right.
- Learn: Pagination in DynamoDB
References
- Paginating table query results in DynamoDB — Amazon DynamoDB Developer Guide
- Query — Amazon DynamoDB API Reference
- Scan — Amazon DynamoDB API Reference
Last verified 2026-07-13 against the official AWS documentation linked above.