ExpressionAttributeNames contains invalid key: Syntax error

TL;DR — 问题出在你 ExpressionAttributeNames map 左侧的占位符键上,而不是它指向的属性。一个占位符必须是 # 后跟纯字母、数字或下划线(#name#p0)。如果你把真实的属性名——连同它的点、连字符、+ 号或空格——放进占位符本身,DynamoDB 会拒绝这个 map。让占位符保持无趣;把杂乱的真实名称放在右侧。

含义

ValidationException: ExpressionAttributeNames contains invalid key:
Syntax error; key: "#my.attribute"

ExpressionAttributeNames 把一个占位符标记(用在你的表达式内部)映射到一个真实的属性名。DynamoDB 在接触你的数据之前会验证占位符的语法:它必须以 # 开头,且只包含在表达式标记内部有效的字符。在表达式语法中有含义的特殊字符——.(路径分隔符)、-+、空格——会使占位符本身无法解析,整个请求都会以这个 ValidationException 被拒绝。

为什么会发生

  • 真实的属性名被复制进了占位符——例如 {"#stats.daily": "stats.daily"}。_键_中的点是一个语法错误,无论它映射到什么。
  • 占位符中的特殊字符——连字符(#user-id)、+ 号或空格。# 之后只有字母数字和下划线是安全的。
  • 缺少 #——ExpressionAttributeNames 中的键必须以 # 开头;{"name": "name"} 是无效的。
  • 一个从属性名自动生成占位符的库,其属性名包含点或特殊字符,把该字符直接透传了过去。

如何修复

  1. 使用简单的占位符并把每个映射到真实名称:

    {
      ExpressionAttributeNames: {'#p0': 'user-id', '#p1': 'stats'},
      KeyConditionExpression: '#p0 = :uid'
    }
  2. 对于嵌套路径,分别为每个段起别名——每个路径元素一个占位符,在表达式中用字面的点连接:

    // read stats.daily where the item has a top-level "stats" map
    {
      ProjectionExpression: '#s.#d',
      ExpressionAttributeNames: {'#s': 'stats', '#d': 'daily'}
    }

    注意反面情况:如果属性的_实际名称_包含一个字面的点(一个名为 "stats.daily" 的属性,而非嵌套路径),那么为整个名称用一个占位符正是你想要的——{'#sd': 'stats.daily'}——这样点就被当作名称的一部分,而非路径分隔符。

  3. 检查你的封装生成了什么——如果一个 ODM/辅助工具为你构建了这个 map,记录最终请求并检查它生成的占位符键。

在处理名称满是点和横线的属性?DynoTable 桌面应用会自动用正确起别名的名称构建查询,无论属性叫什么。

相关错误

References

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

无需控制台即可使用 DynamoDB

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