title: DynamoDB query secondary index ValidationException: Condition parameter type does not match schema type
body: <p>I am developing an AWS service using the Serverless Framework.  So far it has one table and a couple global secondary indexes.  I'm trying to query against a global secondary index.</p>
  
  <p>Query:</p>
  
  <pre><code>{
      "TableName": "messages-table-dev",
      "IndexName": "roomIndex",
      "KeyConditionExpression": "room = :room",
      "ExpressionAttributeValues": {
          ":room": {
              "S": "everyone"
          }
      }
  }
  </code></pre>
  
  <p>It gives an exception -- using the Node.js DynamoDB client, not the Node.js DocumentClient</p>
  
  <pre><code>ValidationException: One or more parameter values were invalid: Condition parameter type does not match schema type
  at Request.extractError (/var/task/node_modules/aws-sdk/lib/protocol/json.js:48:27)
  at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
  at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
  at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:683:14)
  at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
  at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
  at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
  at Request.&lt;anonymous&gt; (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
  at Request.&lt;anonymous&gt; (/var/task/node_modules/aws-sdk/lib/request.js:685:12)
  at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
  message: 'One or more parameter values were invalid: Condition parameter type does not match schema type',
  code: 'ValidationException',
  time: 2018-06-05T05:11:08.899Z,
  requestId: '72OROVKI35I3QDO2IJNQH6SIRVVV4KQNSO5AEMVJF66Q9ASUAAJG',
  statusCode: 400,
  retryable: false,
  retryDelay: 35.265782751506215
  </code></pre>
  
  <p>I understand from the documentation that KeyConditionExpression must do an equality match on the partition index.  In this case the <code>room</code> field is the partition index of the <code>roomIndex</code> global secondary index.  According to the documentation, you substitute values into the expression using the ExpressionAttributeValues array, and as far as I can determine this is constructed correctly.</p>
  
  <p>The exception message is making me think of a type mismatch between the supplied value in the query and the type of the column being queried.  Is that the correct interpretation?  But that cannot be the case - as you can see below, the <code>room</code> column is defined as <code>S</code> for String.  Hence this is a string comparison and should be fine.</p>
  
  <p>Again - I am not using the DocumentClient.  I've seen plenty of answers suggesting to simplify the query by using that client.  I'm not using it.</p>
  
  <p>The table is defined in the Serverless <code>serverless.yml</code> as so:</p>
  
  <pre><code>MessagesDynamoDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: messageId
          AttributeType: S
        - AttributeName: room
          AttributeType: S
        - AttributeName: userId
          AttributeType: S
      KeySchema:
        - AttributeName: messageId
          KeyType: HASH
      GlobalSecondaryIndexes:
        - IndexName: roomIndex
          KeySchema:
            - AttributeName: room
              KeyType: HASH
          Projection:
            ProjectionType: ALL
          ProvisionedThroughput:
            ReadCapacityUnits: 1
            WriteCapacityUnits: 1
        - IndexName: userIndex
          KeySchema:
            - AttributeName: userId
              KeyType: HASH
          Projection:
            ProjectionType: ALL
          ProvisionedThroughput:
            ReadCapacityUnits: 1
            WriteCapacityUnits: 1
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1
      TableName: ${self:custom.tableName}
  </code></pre>
  
  <p>The table has a simple primary key and then two Global indexes each with simple primary keys.</p>
  
  <p>The query code:</p>
  
  <pre><code>const params = {
      TableName: MESSAGES_TABLE,
      IndexName: "roomIndex",
      KeyConditionExpression: "room = :room",
      ExpressionAttributeValues: {
          ":room": { S: `${req.params.room}` }
      },
  };
  console.log(`QUERY ROOM ${JSON.stringify(params)}`);
  
  dynamoDb.query(params, (error, result) =&gt; {
      if (error) {
          console.log(error);
          res.status(400).json({ error: 'Could not get messages' });
      } else {
          res.json(result.Items);
      }
  });
  </code></pre>