ValidationException: Invalid UpdateExpression
TL;DR — Your UpdateExpression is malformed. Nine times out of ten it's a reserved keyword (like status, name, size) used directly — swap it for a #placeholder in ExpressionAttributeNames. The message names the exact token.
What it means
Typical messages:
ValidationException: Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: status
ValidationException: Invalid UpdateExpression: Syntax error; token: "=", near: "SET status ="
ValidationException: Invalid UpdateExpression: An expression attribute value used in expression is not defined; attribute value: :sDynamoDB parses the expression string and rejects anything that isn't valid grammar or references an undefined placeholder.
Why it happens
- Reserved keyword used raw. DynamoDB has hundreds of reserved words —
status,name,size,count,data,year. Used directly in an expression they cause a syntax error. - Missing
ExpressionAttributeNamesentry for a#nameyou referenced. - Missing
ExpressionAttributeValuesentry for a:valueyou referenced. - Wrong verb grammar — mixing clauses incorrectly (
SET,REMOVE,ADD,DELETEeach have their own syntax), or a stray=. - Attribute name with special characters (dots, dashes) used without a placeholder.
How to fix it
- Alias every attribute name through
ExpressionAttributeNames(#status) — it sidesteps the reserved-word list entirely, so aliasing everything is a safe habit. - Define every
:valueyou reference inExpressionAttributeValues. - Use the right clause.
SETto write/overwrite,REMOVEto delete an attribute,ADDfor atomic number/set increments,DELETEto remove from a set.
Example
import {DynamoDBClient} from '@aws-sdk/client-dynamodb';
import {DynamoDBDocumentClient, UpdateCommand} from '@aws-sdk/lib-dynamodb';
const doc = DynamoDBDocumentClient.from(new DynamoDBClient({}));
await doc.send(
new UpdateCommand({
TableName: 'Orders',
Key: {pk: 'ORDER#1'},
// #status aliases the reserved word "status"
UpdateExpression: 'SET #status = :s, updatedAt = :t',
ExpressionAttributeNames: {'#status': 'status'},
ExpressionAttributeValues: {':s': 'SHIPPED', ':t': Date.now()}
})
);