ExpressionAttributeNames contains invalid key: Syntax error

TL;DR — Le problème vient de la clé de placeholder située à gauche de ta map ExpressionAttributeNames, pas de l'attribut vers lequel elle pointe. Un placeholder doit être un # suivi de simples lettres, chiffres ou underscores (#name, #p0). Si tu mets le vrai nom d'attribut — avec ses points, tirets, signes + ou espaces — dans le placeholder lui-même, DynamoDB rejette la map. Garde des placeholders banals ; mets le vrai nom compliqué du côté droit.

Ce que ça signifie

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

ExpressionAttributeNames associe un jeton de placeholder (utilisé dans ton expression) à un vrai nom d'attribut. DynamoDB valide la syntaxe du placeholder avant de toucher à tes données : il doit commencer par # et ne contenir que des caractères valides dans un jeton d'expression. Les caractères spéciaux qui ont un sens dans la grammaire d'expression — . (séparateur de chemin), -, +, espaces — rendent le placeholder lui-même impossible à analyser, et toute la requête est rejetée avec cette ValidationException.

Pourquoi ça arrive

  • Le vrai nom d'attribut a été copié dans le placeholder — par ex. {"#stats.daily": "stats.daily"}. Le point dans la clé est une erreur de syntaxe, quel que soit ce vers quoi il pointe.
  • Des caractères spéciaux dans le placeholder — tirets (#user-id), signes + ou espaces. Seuls les caractères alphanumériques et les underscores sont sûrs après le #.
  • Un # manquant — les clés de ExpressionAttributeNames doivent commencer par # ; {"name": "name"} est invalide.
  • Une bibliothèque qui auto-génère des placeholders à partir de noms d'attributs contenant des points ou des caractères spéciaux, laissant passer le caractère tel quel.

Comment la corriger

  1. Utilise des placeholders simples et associe chacun au vrai nom :

    {
      ExpressionAttributeNames: {'#p0': 'user-id', '#p1': 'stats'},
      KeyConditionExpression: '#p0 = :uid'
    }
  2. Pour les chemins imbriqués, aliase chaque segment séparément — un placeholder par élément de chemin, joints par un point littéral dans l'expression :

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

    Note le revers : si le nom réel de l'attribut contient un point littéral (un seul attribut nommé "stats.daily", pas un chemin imbriqué), un seul placeholder pour le nom entier est exactement ce qu'il te faut — {'#sd': 'stats.daily'} — pour que le point soit traité comme faisant partie du nom, et non comme un séparateur de chemin.

  3. Vérifie ce que génère ton wrapper — si un ODM/helper construit la map à ta place, journalise la requête finale et inspecte les clés de placeholder qu'il a produites.

Tu travailles avec des attributs dont les noms sont pleins de points et de tirets ? L'application de bureau DynoTable construit ses requêtes avec des noms correctement aliasés automatiquement, quel que soit le nom de l'attribut.

Erreurs liées

Références

Dernière vérification le 2026-07-13 par rapport à la documentation officielle AWS liée ci-dessus.

Travaille avec DynamoDB sans la Console

DynoTable est un client de bureau rapide pour DynamoDB — parcours les tables, exécute des requêtes de style SQL et édite les items en local.