Skip to content

DynamoDBDocumentClient double-marshalls ExpressionAttributeValues when key contains special characters #6997

@Karthik-Wagle

Description

@Karthik-Wagle

Checkboxes for prior research

Describe the bug

When querying with DynamoDBDocumentClient, if the attribute name (defined via ExpressionAttributeNames) includes special characters like #, the associated ExpressionAttributeValues get marshalled twice.
This results in a malformed query, where the value is first wrapped as { S: value } but then incorrectly wrapped again as a nested M (map) structure.
This was observed using middleware to log the command input before and after marshalling.

Regression Issue

  • Select this option if this issue appears to be a regression.

SDK version number

@aws-sdk/[email protected], @aws-sdk/[email protected]

Which JavaScript Runtime is this issue in?

Node.js

Details of the browser/Node.js/ReactNative version

Node version: 18.20.3

Reproduction Steps

  1. Use DynamoDBDocumentClient to send a QueryCommand
  2. Set ExpressionAttributeNames to include a key with special characters (e.g., customerId#upin)

Sample code:

`const {
  DynamoDBClient
} = require('@aws-sdk/client-dynamodb');
const {
  DynamoDBDocumentClient,
  QueryCommand
} = require('@aws-sdk/lib-dynamodb');

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

async function query() {
  const input = {
    TableName: 'example-table',
    KeyConditionExpression: '#key = :partitionKey',
    ExpressionAttributeNames: {
      '#key': 'firstName#lastName',
    },
    ExpressionAttributeValues: {
      ':partitionKey': 'abc#xyz',
    },
    Limit: 1,
    ScanIndexForward: false,
  };

  const command = new QueryCommand(input);

  command.middlewareStack.addRelativeTo(
    (next) => async (args) => {
      console.log('pre-marshall:', args.input);
      return next(args);
    },
    {
      relation: 'before',
      toMiddleware: 'DocumentMarshall',
    }
  );

  command.middlewareStack.addRelativeTo(
    (next) => async (args) => {
      console.log('post-marshall:', args.input);
      return next(args);
    },
    {
      relation: 'after',
      toMiddleware: 'DocumentMarshall',
    }
  );

  try {
    await docClient.send(command);
  } catch (err) {
    console.error('Query failed:', err);
  }
}

query();
`

Observed Behavior

Marshalling is happening twice when the key contains special characters.

Error log:
"One or more parameter values were invalid: Condition parameter type does not match schema type"

Below are the logs captured via middleware:

pre-marshall:
{
  KeyConditionExpression: '#key = :partitionKey',
  ExpressionAttributeValues: { ':partitionKey': '111#xyz' },
  ExpressionAttributeNames: { '#key': 'customerId#upin' },
  Limit: 1,
  ScanIndexForward: false,
  TableName: 'table'
}

post-marshall:
{
  KeyConditionExpression: '#key = :partitionKey',
  ExpressionAttributeValues: { ':partitionKey': { S: '111#xyz' } },
  ExpressionAttributeNames: { '#key': 'customerId#upin' },
  Limit: 1,
  ScanIndexForward: false,
  TableName: 'table'
}

Then marshalling happens again:

pre-marshall:
{
  KeyConditionExpression: '#key = :partitionKey',
  ExpressionAttributeValues: { ':partitionKey': { S: '111#xyz' } },
  ExpressionAttributeNames: { '#key': 'customerId#upin' },
  Limit: 1,
  ScanIndexForward: false,
  TableName: 'table'
}

post-marshall:
{
  KeyConditionExpression: '#key = :partitionKey',
  ExpressionAttributeValues: { ':partitionKey': { M: [Object] } },
  ExpressionAttributeNames: { '#key': 'customerId#upin' },
  Limit: 1,
  ScanIndexForward: false,
  TableName: 'table'
}

Expected Behavior

The value in ExpressionAttributeValues should be marshalled only once, even if the corresponding attribute name contains special characters.

Possible Solution

No response

Additional Information/Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue is a bug.needs-triageThis issue or PR still needs to be triaged.potential-regressionMarking this issue as a potential regression to be checked by team member

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions