ExpressionAttributeNames contains invalid key: Syntax error

TL;DR — El problema es la clave del marcador de posición en el lado izquierdo de tu mapa ExpressionAttributeNames, no el atributo al que apunta. Un marcador de posición debe ser # seguido de letras, dígitos o guiones bajos simples (#name, #p0). Si pones el nombre real del atributo — con sus puntos, guiones, signos + o espacios — dentro del propio marcador, DynamoDB rechaza el mapa. Mantén los marcadores de posición aburridos; pon el nombre real desordenado en el lado derecho.

Qué significa

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

ExpressionAttributeNames mapea un token de marcador de posición (usado dentro de tu expresión) a un nombre de atributo real. DynamoDB valida la sintaxis del marcador de posición antes de tocar tus datos: debe empezar por # y contener solo caracteres válidos dentro de un token de expresión. Los caracteres especiales que significan algo en la gramática de la expresión — . (separador de ruta), -, +, espacios — hacen que el propio marcador de posición no sea analizable, y toda la solicitud se rechaza con esta ValidationException.

Por qué ocurre

  • El nombre real del atributo se copió en el marcador de posición — p. ej. {"#stats.daily": "stats.daily"}. El punto en la clave es un error de sintaxis, independientemente de lo que mapee.
  • Caracteres especiales en el marcador de posición — guiones (#user-id), signos + o espacios. Solo los alfanuméricos y los guiones bajos son seguros después del #.
  • Un # ausente — las claves de ExpressionAttributeNames deben empezar por #; {"name": "name"} es inválido.
  • Una librería que autogenera marcadores de posición a partir de nombres de atributo que contienen puntos o caracteres especiales, pasando el carácter directamente.

Cómo solucionarlo

  1. Usa marcadores de posición simples y mapea cada uno al nombre real:

    {
      ExpressionAttributeNames: {'#p0': 'user-id', '#p1': 'stats'},
      KeyConditionExpression: '#p0 = :uid'
    }
  2. Para rutas anidadas, alias cada segmento por separado — un marcador de posición por elemento de ruta, unidos por un punto literal en la expresión:

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

    Fíjate en el reverso: si el nombre real del atributo contiene un punto literal (un atributo llamado "stats.daily", no una ruta anidada), un único marcador de posición para el nombre completo es exactamente lo que quieres — {'#sd': 'stats.daily'} — para que el punto se trate como parte del nombre, no como un separador de ruta.

  3. Comprueba qué genera tu wrapper — si un ODM/helper construye el mapa por ti, registra la solicitud final e inspecciona las claves de marcador de posición que produjo.

¿Trabajas con atributos cuyos nombres están llenos de puntos y guiones? La app de escritorio DynoTable construye sus consultas con nombres correctamente aliasados de forma automática, se llame como se llame el atributo.

Errores relacionados

Referencias

Verificado por última vez el 2026-07-13 contra la documentación oficial de AWS enlazada arriba.

Trabaja con DynamoDB sin la Consola

DynoTable es un cliente de escritorio rápido para DynamoDB: explora tablas, ejecuta consultas estilo SQL y edita Items localmente.