Two document paths overlap with each other

TL;DR — 一個 UpdateExpression 對每條 document path 只能觸及一次,且沒有路徑可以位於同一 expression 也觸及的另一條路徑_內部_。SET profile = :p, profile.email = :e 重疊了(profile.email 住在 profile 內部);將同一屬性指名兩次也是。將子層折入父層值,或拆成兩次更新。

這是什麼意思

ValidationException: 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 不猜測,而是直接拒絕該 expression。(相同的重疊檢查適用於 ProjectionExpression 中的重複路徑。)

為什麼會發生

  • 在一個 expression 中設定父層與其子層SET profile = :p, profile.email = :e。第二條路徑在第一條內部。
  • 同一屬性出現兩次SET updatedAt = :a REMOVE updatedAt,或 SET tags = :t ADD tags :more
  • ODM/包裝器默默加上一條你也設定的路徑 — 經典情況:程式庫自動寫入時間戳或整個物件(SET item = :obj),而你的程式碼也設定 item.field(在 Dynamoose 帶自動 createdAt/updatedAt 時可見)。
  • 一起更新 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. 去重 — 確保每個屬性在 SET/REMOVE/ADD/DELETE 中恰好出現於一個動作。

  4. 檢查你程式庫的自動欄位 — 在你自己的 expression 已寫入它們的更新中,停用或排除自動管理的屬性(時間戳、版本)。

  5. 當你確實需要「替換父層,然後調整子層」語義時拆成兩個請求 — 兩個 UpdateItem 呼叫,依序。

手動編輯巢狀 map 是重疊溜入之處 — DynoTable 桌面應用程式就地編輯項目的屬性,並為確切變更的內容發出乾淨、不重疊的更新。

相關錯誤

References

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

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

DynoTable 是一款快速的 DynamoDB 桌面用戶端 — 瀏覽表格、執行 SQL 風格的查詢,並在本機編輯項目。