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 的自動createdAt/updatedAt上見過)。 - 同時更新一個 list 與它的某個元素 —
SET mylist = :l, mylist[0] = :v。
如何修正
把子項摺進父項的值裡 — 如果你本來就要取代整個 map,就把新的 email 放進去,並移除第二個動作:
// instead of SET profile = :p, profile.email = :e UpdateExpression: 'SET #p = :p', ExpressionAttributeValues: {':p': {name: 'Ada', email: 'ada@example.com'}}或只更新葉節點 — 讓父項保持不動,個別設定巢狀欄位(
SET #p.#n = :n, #p.#e = :e)。同一個父項底下的兄弟路徑並不重疊;只有巢狀關係才算。去重複 — 確認每個屬性在
SET/REMOVE/ADD/DELETE之中只出現在恰好一個動作裡。檢查你函式庫的自動欄位 — 在你自己的運算式已經會寫入時,停用或排除那些自動管理的屬性(時間戳、版本)。
當你真的需要「先取代父項、再調整子項」的語意時,就拆成兩個請求 — 兩次依序的
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 選擇拒絕而不是挑一個。
相關錯誤
- The document path provided is invalid for update — 另一種巢狀路徑的更新失敗(是父項不存在,而不是被寫了兩次)。
- Invalid UpdateExpression:語法錯誤
- 學習:更新運算式
參考資料
- Using update expressions in DynamoDB — Amazon DynamoDB Developer Guide
- Referring to item attributes when using expressions in DynamoDB — Amazon DynamoDB Developer Guide
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
最後於 2026-07-13 對照上方連結的官方 AWS 文件驗證。
已於 2026-07-26 對照 DynamoDB Local 2.x 與 AWS SDK for JavaScript v3.1095.0 重現 — 上方輸出為逐字原文。