Skip to content

DocumentTransactWrite.AddDocumentToUpdateHelper throws NullReferenceException for null ExpressionAttributeNames/Values #4071

@steven-kehrli-netdocuments

Description

Describe the bug

The DocumentTransactWrite.AddDocumentToUpdateHelper method throws a NullReferenceException when either updateExpression.ExpressionAttributeNames, updateExpression.ExpressionAttributeValues, conditionalExpression.ExpressionAttributeNames, or conditionalExpression.ExpressionAttributeValues are null.

The TryFilterDuplicates method (called at lines 446 and 457 in DocumentTransactWrite.cs) does not perform null checking on its dictionary parameters before iterating over them, causing a NullReferenceException when these properties are null.

According to the DynamoDB Document Model API documentation and the Expression class design, these properties can be null (they are not marked as required/non-null), yet the SDK does not handle this case defensively.

Regression Issue

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

Expected Behavior

The SDK should handle null ExpressionAttributeNames and ExpressionAttributeValues properties gracefully. When these properties are null, the SDK should treat them as "no attributes of this type" and continue processing without throwing exceptions.

The TryFilterDuplicates method should implement null-safe logic to handle cases where either or both dictionary parameters are null.

Current Behavior

A NullReferenceException is thrown when calling AddDocumentToUpdateHelper with an updateExpression or conditionalExpression that has null ExpressionAttributeNames or ExpressionAttributeValues properties.

Stack trace occurs in TryFilterDuplicates when attempting to iterate over a null dictionary.

Reproduction Steps

var updateExpression = new Expression
{
    ExpressionStatement = "SET #status = :status",
    ExpressionAttributeNames = new Dictionary<string, string> { ["#status"] = "Status" },
    ExpressionAttributeValues = null  // This causes the issue
};

var conditionalExpression = new Expression
{
    ExpressionStatement = "attribute_exists(Id)",
    ExpressionAttributeNames = new Dictionary<string, string> { ["#Id"] = "Id" },
    ExpressionAttributeValues = null  // Or this
};

var config = new TransactWriteItemsOperationConfig
{
    ConditionalExpression = conditionalExpression
};

// This throws NullReferenceException
transactWrite.AddDocumentToUpdate(..., updateExpression, config);

Possible Solution

private static bool TryFilterDuplicates<T>(
    Dictionary<string, T> src, 
    Dictionary<string, T> other,
    out Dictionary<string, T> dest, 
    out List<string> conflictingKeys)
{
    conflictingKeys = new List<string>();

    // If src is null, there's nothing to filter - return null
    if (src == null)
    {
        dest = null;
        return true;
    }

    // If other is null, all of src is unique - return src as-is
    if (other == null)
    {
        dest = src;
        return true;
    }

    // Both exist - filter for unique and conflicting keys as normal
    dest = new Dictionary<string, T>();
    // ... existing foreach logic
}

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

AWSSDK.DynamoDBv2 4.0.8

Targeted .NET Platform

.NET 8.0

Operating System and version

macOS 15.x (Darwin 24.6.0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue is a bug.dynamodbp1This is a high priority issuequeuedxsEffort estimation: tiny

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions