Skip to content

PHOENIX-7900: Return HTTP 400 for missing ExpressionAttributeValues#9

Open
jinggou wants to merge 6 commits into
apache:mainfrom
jinggou:PHOENIX-7900
Open

PHOENIX-7900: Return HTTP 400 for missing ExpressionAttributeValues#9
jinggou wants to merge 6 commits into
apache:mainfrom
jinggou:PHOENIX-7900

Conversation

@jinggou

@jinggou jinggou commented Jun 15, 2026

Copy link
Copy Markdown

Jira: PHOENIX-7900

Query API was throwing NullPointerException (HTTP 500) when required ExpressionAttributeValues placeholders were missing. Now validates that all referenced placeholders exist and throws ValidationException (HTTP 400) with clear error messages.

Changes:

  • QueryService: Add validation before accessing ExpressionAttributeValues
  • Add QueryMissingExpressionAttributeValueIT: Integration tests
  • Add QueryServiceValidationTest: Unit tests

All existing tests pass with no regressions.

Query API was throwing NullPointerException (HTTP 500) when required
ExpressionAttributeValues placeholders were missing. Now validates
that all referenced placeholders exist and throws ValidationException
(HTTP 400) with clear error messages.

Changes:
- QueryService: Add validation before accessing ExpressionAttributeValues
- Add QueryMissingExpressionAttributeValueIT: Integration tests
- Add QueryServiceValidationTest: Unit tests

All existing tests pass with no regressions.
@virajjasani virajjasani self-requested a review June 15, 2026 18:24

@palashc palashc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can widen the scope of this JIRA to look at other APIs and code paths which might need this fix. Also there are test failures

Error:  Failures: 
Error:    QueryMissingExpressionAttributeValueIT.testQueryWithMissingBetweenValue:228 Expected ValidationException in: ExpressionAttributeValues missing required placeholder ':v2' for sort key BETWEEN condition (Service: DynamoDb, Status Code: 400, Request ID: null)
Error:    QueryMissingExpressionAttributeValueIT.testQueryWithMissingPartitionKeyValue:139 Expected ValidationException in: ExpressionAttributeValues missing required placeholder ':v0' for partition key (Service: DynamoDb, Status Code: 400, Request ID: null)
Error:    QueryMissingExpressionAttributeValueIT.testQueryWithMissingSortKeyValue:184 Expected ValidationException in: ExpressionAttributeValues missing required placeholder ':v1' for sort key condition (Service: DynamoDb, Status Code: 400, Request ID: null)

String beginsWithPlaceholder = keyConditions.getBeginsWithSortKeyVal();
if (!exprAttrVals.containsKey(beginsWithPlaceholder)) {
throw new ValidationException(String.format(
"ExpressionAttributeValues missing required placeholder '%s' for sort key begins_with condition",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exception message should mirror what localddb throws for this scenario

jinggou added 2 commits June 18, 2026 14:38
Changes based on PR review comments:
- Move validation logic to ValidationUtil.requireExpressionAttributeValue() for reusability
- Match AWS DynamoDB error message format exactly
- Remove QueryServiceValidationTest (didn't exercise production code)
- Add comprehensive test coverage: null values, malformed AttributeValues, begins_with
- Fix test assertions to check awsErrorDetails().errorCode() for ValidationException

All 180+ Query integration tests pass with no regressions.
Simplified the fix:
- Moved null check directly to DQLUtils.setKeyValueOnStatement() where NPE occurred
- Removed ValidationUtil.requireExpressionAttributeValue() utility method
- Reverted QueryService to simple .get() calls
- Added placeholderName parameter to show actual missing placeholder in error
- Integrated 3 tests into existing QueryIT.java (no new IT class)
- Deleted separate QueryMissingExpressionAttributeValueIT.java

Error message now includes actual placeholder name:
"Value provided in ExpressionAttributeValues unused in expressions: keys: {:status}"

All services calling setKeyValueOnStatement updated:
- QueryService: passes ExpressionAttributeValues placeholders (:v0, :v1, etc.)
- ScanService, GetItemService, BatchGetItemService: pass column names
Comment on lines +189 to +194
Map<String, Object> attrVal, String placeholderName, boolean isBeginsWith) throws SQLException {
if (attrVal == null) {
throw new ValidationException(
"Value provided in ExpressionAttributeValues unused in expressions: keys: {"
+ placeholderName + "}");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep the changes simpler, let's not even use placeholderName in exception message so that method signature remains same and all service implementations don't need to change

@palashc palashc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, pending one nit addressed and build results

Comment thread phoenix-ddb-rest/src/main/java/org/apache/phoenix/ddb/service/utils/DQLUtils.java Outdated
@palashc palashc added bug Something isn't working good first issue Good for newcomers labels Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants