Describe the bug
When calling Ec2Client#describeInstances with one or more filter expressions, the filters contain numbers formatted using the current locale rather than the root locale. Thus for instance running in the ne (Nepalese) local the query uses Filter.%E0%A5%A7.Name rather than Filter.1.Name, where %E0%A5%A7 is the UTF-8 encoding for U+0967 DEVANAGARI DIGIT ONE which is the rendering for the integer 1 in this locale. The full HTTP request in this case is as follows:
POST / HTTP/1.1
Host: 127.0.0.1:60608
amz-sdk-invocation-id: a5d80d84-b502-096b-bef6-da85818cb947
amz-sdk-request: attempt=1; max=10
Authorization: AWS4-HMAC-SHA256 Credential=ec2_key/20250318/es-test-region/ec2/aws4_request, SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;content-length;content-type;host;x-amz-content-sha256;x-amz-date, Signature=749ddaeccbe94b749d6c1e7446a070dcca7ec2845068053883f28fdd9129ded3
Content-Type: application/x-www-form-urlencoded; charset=utf-8
User-Agent: aws-sdk-java/2.30.38 md/io#sync md/http#Apache ua/2.1 os/Mac_OS_X#15.3.2 lang/java#23 md/OpenJDK_64-Bit_Server_VM#23+37 md/vendor#Eclipse_Adoptium md/en_GB cfg/auth-source#stat m/D
x-amz-content-sha256: 1380541b646459c65b2316cb6c26f03a41760ebe57c48ecbe55697c5da1b3938
X-Amz-Date: 20250318T142438Z
Content-Length: 239
Connection: Keep-Alive
Action=DescribeInstances&Version=2016-11-15&Filter.%E0%A5%A7.Name=instance-state-name&Filter.%E0%A5%A7.Value.%E0%A5%A7=running&Filter.%E0%A5%A7.Value.%E0%A5%A8=pending&Filter.%E0%A5%A8.Name=tag%3Astage&Filter.%E0%A5%A8.Value.%E0%A5%A7=prod
EC2 rejects this with a 400 Bad request:
[2025-03-19T09:36:24,478][DEBUG][o.e.d.e.AwsEc2SeedHostsProvider] [node-0] Full exception:software.amazon.awssdk.services.ec2.model.Ec2Exception: Value (१) for parameter QueryStringParameter is invalid. Invalid or illegal XML character specified (Service: Ec2, Status Code: 400, Request ID: 7405f831-6f63-4bd1-b54f-f96be228b4c8) (SDK Attempt Count: 1)
The problem is that software.amazon.awssdk.protocols.query.internal.marshall.ListQueryMarshaller#EC2_QUERY_PATH_RESOLVER uses a bare String.format("%s.%d", path, i + 1) rather than String.format(Locale.ROOT, "%s.%d", path, i + 1)
Regression Issue
Expected Behavior
In all locales, we should render the filters using ASCII digits 0 to 9 only:
Action=DescribeInstances&Version=2016-11-15&Filter.1.Name=instance-state-name&Filter.1.Value.1=running&Filter.1.Value.2=pending&Filter.2.Name=tag%3Astage&Filter.2.Value.1=prod
Current Behavior
We render the filters using locale-dependent numerals, UTF-8-encoded, for instance in the ne locale:
Action=DescribeInstances&Version=2016-11-15&Filter.%E0%A5%A7.Name=instance-state-name&Filter.%E0%A5%A7.Value.%E0%A5%A7=running&Filter.%E0%A5%A7.Value.%E0%A5%A8=pending&Filter.%E0%A5%A8.Name=tag%3Astage&Filter.%E0%A5%A8.Value.%E0%A5%A7=prod
Reproduction Steps
Attempt to invoke Ec2Client#describeInstances in a locale that does not render numerals using the ASCII digits 0 to 9, such as for instance ne.
Possible Solution
diff --git a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java
index 971dbb96f95..4323fd80b1c 100644
--- a/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java
+++ b/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.java
@@ -31,7 +31,7 @@ public class ListQueryMarshaller implements QueryMarshaller<List<?>> {
listTrait.isFlattened() ?
String.format("%s.%d", path, i + 1) :
String.format("%s.%s.%d", path, listTrait.memberFieldInfo().locationName(), i + 1);
- private static final PathResolver EC2_QUERY_PATH_RESOLVER = (path, i, listTrait) -> String.format("%s.%d", path, i + 1);
+ private static final PathResolver EC2_QUERY_PATH_RESOLVER = (path, i, listTrait) -> String.format(Locale.ROOT, "%s.%d", path, i + 1);
private static final EmptyListMarshaller AWS_QUERY_EMPTY_LIST_MARSHALLER =
(context, path) -> context.request().putRawQueryParameter(path, "");
Additional Information/Context
No response
AWS Java SDK version used
2.30.38
JDK version used
OpenJDK Runtime Environment Temurin-23+37 (build 23+37)
Operating System and version
Mac OS X 15.3.2 aarch64/Oracle Corporation 23 (64-bit)/cpus=12,threads=1,free=493903224,total=536870912
Describe the bug
When calling
Ec2Client#describeInstanceswith one or more filter expressions, the filters contain numbers formatted using the current locale rather than the root locale. Thus for instance running in thene(Nepalese) local the query usesFilter.%E0%A5%A7.Namerather thanFilter.1.Name, where%E0%A5%A7is the UTF-8 encoding forU+0967 DEVANAGARI DIGIT ONEwhich is the rendering for the integer1in this locale. The full HTTP request in this case is as follows:EC2 rejects this with a
400 Bad request:The problem is that
software.amazon.awssdk.protocols.query.internal.marshall.ListQueryMarshaller#EC2_QUERY_PATH_RESOLVERuses a bareString.format("%s.%d", path, i + 1)rather thanString.format(Locale.ROOT, "%s.%d", path, i + 1)Regression Issue
Expected Behavior
In all locales, we should render the filters using ASCII digits
0to9only:Current Behavior
We render the filters using locale-dependent numerals, UTF-8-encoded, for instance in the
nelocale:Reproduction Steps
Attempt to invoke
Ec2Client#describeInstancesin a locale that does not render numerals using the ASCII digits0to9, such as for instancene.Possible Solution
Additional Information/Context
No response
AWS Java SDK version used
2.30.38
JDK version used
OpenJDK Runtime Environment Temurin-23+37 (build 23+37)Operating System and version
Mac OS X 15.3.2 aarch64/Oracle Corporation 23 (64-bit)/cpus=12,threads=1,free=493903224,total=536870912