Two document paths overlap with each other

TL;DR — 一個 UpdateExpression 對每個文件路徑只能觸及一次,而且任何路徑都不能位於同一運算式也觸及的另一個路徑_內部_。SET profile = :p, profile.email = :e 就重疊了(profile.email 住在 profile 裡面);把同一個屬性指名兩次也是。把子項摺進父項的值裡,或拆成兩次更新。

這是什麼意思

ValidationException: 1 validation error detected: Invalid UpdateExpression: Two document paths overlap
with each other; must remove or rewrite one of these paths;
path one: [profile], path two: [profile, email]

DynamoDB 是拿項目更新前的屬性值來對 UpdateExpression 中的每個動作求值 — 動作並不是由左到右一個接一個套用的。如果兩個動作指向重疊的路徑(同一個屬性,或一個父項與巢狀其中的東西),結果就會有歧義:profile.email = :e 是在 profile = :p 取代整個 map 之前還是之後執行?DynamoDB 不去猜,而是直接拒絕這個運算式。(同樣的重疊檢查也適用於 ProjectionExpression 中的重複路徑。)

為什麼會發生

  • 在一個運算式中同時設定父項與其子項SET profile = :p, profile.email = :e。第二個路徑在第一個裡面。
  • 同一個屬性出現兩次SET updatedAt = :a REMOVE updatedAt,或 SET tags = :t ADD tags :more
  • 某個 ODM/包裝層默默加上了你也在設定的路徑 — 經典案例:某個函式庫自動寫入時間戳或整個物件(SET item = :obj),而你的程式碼同時又設定了 item.field(在 Dynamoose 的自動 createdAtupdatedAt 上見過)。
  • 同時更新一個 list 與它的某個元素SET mylist = :l, mylist[0] = :v

如何修正

  1. 把子項摺進父項的值裡 — 如果你本來就要取代整個 map,就把新的 email 放進去,並移除第二個動作:

    // instead of SET profile = :p, profile.email = :e
    UpdateExpression: 'SET #p = :p',
    ExpressionAttributeValues: {':p': {name: 'Ada', email: 'ada@example.com'}}
  2. 或只更新葉節點 — 讓父項保持不動,個別設定巢狀欄位(SET #p.#n = :n, #p.#e = :e)。同一個父項底下的兄弟路徑並不重疊;只有巢狀關係才算。

  3. 去重複 — 確認每個屬性在 SETREMOVEADDDELETE 之中只出現在恰好一個動作裡。

  4. 檢查你函式庫的自動欄位 — 在你自己的運算式已經會寫入時,停用或排除那些自動管理的屬性(時間戳、版本)。

  5. 當你真的需要「先取代父項、再調整子項」的語意時,就拆成兩個請求 — 兩次依序的 UpdateItem 呼叫。

手動編輯巢狀 map 正是重疊偷偷混入的地方 — DynoTable 桌面應用程式會就地編輯項目的屬性,並針對實際變動的部分發出一次乾淨、不重疊的更新。

重現方式

一個 UpdateExpression 同時設定一個 map 與該 map 內部的一個欄位:

await client.send(
  new UpdateItemCommand({
    TableName: 'orders',
    Key: {pk: {S: 'ORDER#1'}, sk: {S: 'META'}},
    UpdateExpression: 'SET #a = :v, #a.#b = :w',
    ExpressionAttributeNames: {'#a': 'addr', '#b': 'city'},
    ExpressionAttributeValues: {':v': {M: {}}, ':w': {S: 'Berlin'}}
  })
);

實際輸出:

ValidationException: 1 validation error detected: Invalid UpdateExpression: Two document paths overlap with each other; must remove or rewrite one of these paths; path one: [addr], path two: [addr, city]
HTTP 400

這則訊息會完整印出兩個衝突的路徑,因此它精確告訴你該調和的是哪一對。如果兩者都被套用,順序是未定義的,這也是為什麼 DynamoDB 選擇拒絕而不是挑一個。

相關錯誤

參考資料

最後於 2026-07-13 對照上方連結的官方 AWS 文件驗證。

已於 2026-07-26 對照 DynamoDB Local 2.x 與 AWS SDK for JavaScript v3.1095.0 重現 — 上方輸出為逐字原文。

不必透過主控台就能操作 DynamoDB

一款快速的 DynamoDB 桌面用戶端,可執行 DynamoDB 無法執行的真正 SQL — JOINs、GROUP BY、聚合 — 並支援視覺化編輯與使用你自己的 Bedrock 金鑰的 AI 代理。

30 天免費試用,無需信用卡 — 之後為無時間限制的免費方案。