ExpressionAttributeNames contains invalid key: Syntax error

TL;DR — 問題は、ExpressionAttributeNames マップの左側の プレースホルダーキー であり、それが指す属性ではありません。プレースホルダーは # の後に素の文字、数字、またはアンダースコアが続くもの(#name#p0)でなければなりません。実際の属性名 — ドット、ハイフン、+ 記号、スペースを含む — をプレースホルダー自体に入れると、DynamoDB はマップを拒否します。プレースホルダーは無味乾燥に保ち、乱雑な実際の名前は右側に置いてください。

意味

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. ネストパスでは、各セグメントを別々にエイリアス化します — パス要素ごとに1つのプレースホルダーを、式内でリテラルのドットで結合します:

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

    逆の側に注意してください: 属性の 実際の名前 にリテラルのドットが含まれる場合(ネストパスではなく "stats.daily" という名前の1つの属性)、名前全体に対する 単一の プレースホルダーがまさに欲しいものです — {'#sd': 'stats.daily'} — こうすればドットはパス区切りではなく名前の一部として扱われます。

  3. ラッパーが何を生成するか確認します — ODM/ヘルパーがマップを組み立てる場合、最終リクエストをログに記録し、生成されたプレースホルダーキーを検査します。

名前がドットやダッシュだらけの属性を扱っていますか?DynoTable デスクトップアプリ は、属性が何と呼ばれていようと、適切にエイリアス化された名前で自動的にクエリを組み立てます。

関連するエラー

References

最終検証日 2026-07-13、上記にリンクした公式 AWS ドキュメントに照らして確認しました。

Console なしで DynamoDB を扱う

DynoTable は DynamoDB 向けの高速なデスクトップクライアントです — テーブルを閲覧し、SQL スタイルのクエリを実行し、アイテムをローカルで編集できます。