Two document paths overlap with each other

TL;DR — 一个 UpdateExpression 对每个文档路径只能触及一次,且没有路径可以位于同一表达式也触及的另一个路径_内部_。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 不去猜,而是直接拒绝这个表达式。(同样的重叠检查也适用于一个 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

如何修复

  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. 检查你的库的自动字段——在你自己的表达式已经写入它们的更新中,禁用或排除自动管理的属性(时间戳、版本)。

  5. 拆成两个请求,当你确实需要"替换父级,然后调整子级"语义时——两次 UpdateItem 调用,按顺序。

手工编辑嵌套 map 正是重叠溜进来之处——DynoTable 桌面应用就地编辑一个项目的属性,并为确切改变的内容发出一个干净、不重叠的更新。

相关错误

References

最后核实于 2026-07-13,依据上方链接的 AWS 官方文档。

无需控制台即可使用 DynamoDB

DynoTable 是面向 DynamoDB 的快速桌面客户端 —— 浏览表、运行 SQL 风格的查询,并在本地编辑项。