Value provided in ExpressionAttributeNames unused in expressions

TL;DR — You declared a name placeholder in ExpressionAttributeNames (e.g. #status) that no expression references. DynamoDB requires every declared alias to be used in a KeyConditionExpression, FilterExpression, UpdateExpression, ConditionExpression, or ProjectionExpression. Remove the unused alias — or fix the expression that was supposed to reference it.

What it means

ValidationException: 1 validation error detected: Value provided in ExpressionAttributeNames unused in
expressions: keys: {#status}

# what the engine actually returns, reproduced against DynamoDB Local:
ValidationException: 1 validation error detected: Value provided in ExpressionAttributeNames unused in expressions: keys: {#status}

ExpressionAttributeNames is a substitution map for attribute-name aliases (needed for reserved words or names with special characters). DynamoDB enforces a strict two-way contract: every alias you use in an expression must be declared, and every alias you declare must be used. A leftover, unreferenced entry triggers this HTTP 400 ValidationException. It's client-side and not retryable until the map matches the expressions.

Why it happens

  • A stale alias left after editing an expression — you removed #status = :s from the expression but forgot to delete #status from the names map.
  • A generated map that over-declares — a mapping layer emitted aliases for every attribute even ones the final expression doesn't touch.
  • The alias is in the values map, not names — you meant :status (a value) but declared #status (a name).
  • A typo mismatch — the expression uses #stat while the map declares #status, so #status is technically unused.

How to fix it

  1. Delete the unused alias the message names from ExpressionAttributeNames.
  2. Keep the map in lock-step with the expressions — declare a #name only when an expression actually references it.
  3. Check for a name-vs-value mix-up#-aliases live in ExpressionAttributeNames, :-placeholders in ExpressionAttributeValues.
  4. Regenerate the request so names, values, and expression text are built together rather than assembled by hand.

Inspect in DynoTable

DynoTable aliases reserved attribute names in the update and filter editors — every #placeholder in the output is referenced in the expression. Open a table with ⌘K, edit an item, and copy the generated ExpressionAttributeNames map.

Cross-check failing SDK requests in the reserved words checker — it prints the alias map for names that need # prefixes. Switch profiles with ⌘P; see Connect to AWS and Install.

Sources

Reproduce it

An ExpressionAttributeNames entry that no expression references:

await client.send(
  new UpdateItemCommand({
    TableName: 'orders',
    Key: {pk: {S: 'ORDER#1'}, sk: {S: 'META'}},
    UpdateExpression: 'SET stat = :v', // note: 'stat', not '#unused'
    ExpressionAttributeNames: {'#unused': 'status'},
    ExpressionAttributeValues: {':v': {S: 'shipped'}}
  })
);

Real output:

ValidationException: 1 validation error detected: Value provided in ExpressionAttributeNames unused in expressions: keys: {#unused}
HTTP 400

The message names the offending key, which makes this one of the few DynamoDB validation errors you can act on without reading anything else. It usually appears after an edit removes a placeholder from the expression but leaves its declaration behind.

References

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

Reproduced 2026-07-26 against DynamoDB Local 2.x with AWS SDK for JavaScript v3.1095.0 — the output above is verbatim.

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.