The document path provided in the update expression is invalid for update

TL;DR — You're writing to a nested path (SET parent.child = :v) but parent doesn't exist on the item — or exists as a string/number instead of a map or list. DynamoDB does NOT auto-create intermediate maps. Create the parent first (SET #p = if_not_exists(#p, :emptyMap) in a prior update, or initialize {} when the item is created), then set the nested attribute.

What it means

ValidationException: The document path provided in the update expression
is invalid for update

An update expression can address deep paths (stats.daily.views, items[3].qty), but every step of the path except the last must already exist on the item with a compatible type. If the item has no stats attribute — or stats is a string — there is nowhere to hang daily, and the update is rejected. The same check runs inside transactions, where it surfaces as a ValidationError cancellation reason.

Why it happens

  • The parent map doesn't exist yet — the item was created without stats, and now SET stats.daily = :v has no stats to descend into.
  • The parent exists with the wrong typestats is a string or number, not a map (M), so it has no members to address.
  • Indexing into a missing listSET items[0].qty = :q when items isn't on the item or isn't a list.
  • A typo'd path segmentSET stat.daily = :v (missing s) descends into an attribute that isn't there.
  • Different items have different shapes — the update works on items that carry the map and fails on the ones that don't (common in single-table designs with mixed entities).

How to fix it

  1. Initialize parent maps when you create the item — write stats: {} (an empty M) up front, and nested updates always have somewhere to land.

  2. Or create the parent on demand, then set the child — two updates. DynamoDB won't let you do both in one expression (that's a path overlap):

    // update 1 — create the map only if it's missing
    UpdateExpression: 'SET #s = if_not_exists(#s, :empty)',
    ExpressionAttributeNames: {'#s': 'stats'},
    ExpressionAttributeValues: {':empty': {}}
    
    // update 2 — now the nested set is safe
    UpdateExpression: 'SET #s.#d = :v',
    ExpressionAttributeNames: {'#s': 'stats', '#d': 'daily'}

    Note if_not_exists(stats.daily, :v) does not help here — it guards the value, not the missing parent.

  3. Replace the whole map instead when you own its full shape: SET #s = :wholeMap works whether or not stats existed.

  4. Verify the real item shape — read the item and check the parent attribute exists and is an M/L before assuming the path is valid.

The DynoTable desktop app shows every item's real nested structure at a glance — you can see whether stats is a map, a string, or missing entirely before you write to it.

References

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

Work with DynamoDB without the Console

DynoTable is a fast desktop client for DynamoDB — browse tables, run SQL-style queries, and edit items locally.