Gatling version: 3.15.0
Gatling flavor: java kotlin scala javascript typescript
Gatling build tool: maven gradle sbt bundle npm
Hi everyone,
After upgrading our project to Gatling 3.15.0 (using the io.gatling.gradle plugin), our performance tests started failing with the following exception:
i.g.h.c.i.PrematureCloseException: Premature close
This happens on all requests made to the AWS SQS Query API.
Example request:
exec(
http("My Request")
.get(queueUrl)
.queryParam("Action", "GetQueueAttributes")
.queryParam("AttributeName", "ApproximateNumberOfMessages")
.sign((request, _) => mySignManager.sign(request))
.check(status is 200)
)
The failing requests look like:
GET https://sqs.eu-west-1.amazonaws.com/9999/my-queue
?Action=GetQueueAttributes
&AttributeName=ApproximateNumberOfMessages
What’s interesting is that rolling back the plugin from 3.15.0 to 3.14.9.8 makes the problem disappear, without any other code changes.
So it seems related to something introduced in Gatling 3.15.0 (possibly an HTTP client or Netty upgrade?).
Has anyone else experienced similar issues with PrematureCloseException after upgrading to 3.15?
Thanks!
There’s nothing we can do to help here with absolutely zero information. We need a reproducer.
Hey! Sorry, I accidentally posted the wrong draft. 
I’ve just updated the topic—hopefully it now has the information you need!
Thanks!
Nope, only one signature is made. I also noticed that when I enable logging and use the headers and URL generated by the Gatling request in Insomnia, it works—it only fails when the request is performed via Gatling.
Could you please share your mySignManager so we can reproduce? Without a reproducer, we can’t do anything.
Hey! I can’t share the code itself, but what it does is use software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner to sign the request using the service IAM. There’s nothing really special about the signing mechanism—it’s just standard AWS signing.
Here’s an example:
AwsV4HttpSigner signer = AwsV4HttpSigner.create();
SdkHttpFullRequest unsignedRequest = SdkHttpFullRequest.builder()
.method(SdkHttpMethod.GET)
.uri(URI.create(queueUrl))
.appendRawQueryParameter(“Action”, “GetQueueAttributes”)
.appendRawQueryParameter(“AttributeName”, “ApproximateNumberOfMessages”)
.build();
AwsCredentials credentials = DefaultCredentialsProvider.create().resolveCredentials();
AwsV4HttpSignerParams signingParams = AwsV4HttpSignerParams.builder()
.awsCredentials(credentials)
.signingName(“sqs”)
.signingRegion(Region.EU_WEST_1)
.build();
SdkHttpFullRequest signedRequest = signer.sign(unsignedRequest, signingParams);
Then, after signing the request, we get the generated headers from signedRequest and add them to the Gatling request.
I was not able to reproduce.
You should try to lower the logging level and compare the output with the 2 versions.
If you can’t spot a difference, please provide an example of the problematic request HTTP headers so we can check if Netty has changed anything and is corrupting them.
hey! here’re the logs:
Failure (3.15.0):
i.g.h.e.r.DefaultStatsProcessor -
>>>>>>>>>>>>>>>>>>>>>>>>>>
Request:
My request: KO i.g.h.c.i.PrematureCloseException: Premature close
=========================
Session:
Session(My request,33,Map(gatling.http.ssl.sslContexts -> ..., gatling.http.cache.dns -> ..., gatling.repeat-2 -> 0),KO,...)
=========================
HTTP request:
GET https://sqs.eu-west-1.amazonaws.com/123456789012/my-queue?Action=GetQueueAttributes&AttributeName=ApproximateNumberOfMessages
headers:
accept: */*
Authorization: AWS4-HMAC-SHA256 Credential=<REDACTED>/20260319/eu-west-1/sqs/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=<REDACTED>
x-amz-content-sha256: <REDACTED>
X-Amz-Date: 20260319T171753Z
X-Amz-Security-Token: <REDACTED>
host: sqs.eu-west-1.amazonaws.com
=========================
HTTP response:
<<<<<<<<<<<<<<<<<<<<<<<<<
========================================================================================================================
---- Requests -----------------------------------------------------------------------|---Total---|-----OK----|----KO----
> Global | 33 | 0 | 33
> My request | 23 | 0 | 23
---- Errors ------------------------------------------------------------------------------------------------------------
> i.g.h.c.i.PrematureCloseException: Premature close 33 (100%)
Sucess (3.14.9.8):
i.g.h.e.r.DefaultStatsProcessor -
>>>>>>>>>>>>>>>>>>>>>>>>>>
Request:
My request: OK
=========================
Session:
session(My request, 33, map(gatling.http.ssl.sslcontexts -> ..., gatling.http.cache.dns -> ..., gatling.repeat-2 -> 0), ko, ...)
=========================
HTTP request:
GET https://sqs.eu-west-1.amazonaws.com/123456789012/my-queue?Action=GetQueueAttributes&AttributeName=ApproximateNumberOfMessages
headers:
accept: */*
Authorization: AWS4-HMAC-SHA256 Credential=<REDACTED>/20260319/eu-west-1/sqs/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=<REDACTED>
x-amz-content-sha256: <REDACTED>
X-Amz-Date: 20260319T172634Z
X-Amz-Security-Token: <REDACTED>
host: sqs.eu-west-1.amazonaws.com
=========================
HTTP response:
version:
HTTP/1.1
status:
200 OK
headers:
x-amzn-RequestId: <REDACTED>
Date: Thu, 19 Mar 2026 17:26:34 GMT
Content-Type: text/xml
Content-Length: 357
connection: keep-alive
body:
<?xml version="1.0"?><GetQueueAttributesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><GetQueueAttributesResult><Attribute><Name>ApproximateNumberOfMessages</Name><Value>0</Value></Attribute></GetQueueAttributesResult><ResponseMetadata><RequestId><REDACTED></RequestId></ResponseMetadata></GetQueueAttributesResponse>
<<<<<<<<<<<<<<<<<<<<<<<<<
P.S. i’ve used these log levels:
<logger name="io.gatling.http.engine.response" level="TRACE" />
<logger name="io.gatling.http.engine.tx" level="DEBUG" />
<logger name="io.netty.handler.ssl" level="DEBUG" />
<logger name="io.netty.channel" level="DEBUG" />
Except for the redacted parts, they look identical to me…
You can try going logging one level deeper with CharlesProxy or WireShark and try to spot a difference there…
With no reproducer and no visible difference, there sadly isn’t much we can do.
hey, let me add a few extra details to the session logs:
Failure:
Session(My request,33,Map(gatling.http.ssl.sslContexts → io.gatling.http.util.SslContexts@, gatling.http.cache.dns → io.gatling.http.resolver.ShufflingNameResolver@, gatling.repeat-2 → 0),KO,List(ExitOnCompleteLoopBlock(gatling.repeat-2)),io.gatling.core.protocol.ProtocolComponentsRegistry$$Lambda/,io.netty.channel.SingleThreadIoEventLoop@)
Sucess:
Session(My request,31,Map(gatling.http.ssl.sslContexts → io.gatling.http.util.SslContexts@, gatling.http.cache.dns → io.gatling.http.resolver.ShufflingNameResolver@, → 0),OK,List(ExitOnCompleteLoopBlock()),io.gatling.core.protocol.ProtocolComponentsRegistry$$Lambda/,io.netty.channel.SingleThreadIoEventLoop@)
Not sure if that helps, though…
No, it doesn’t.
I suspect the only way to investigate this is to compare what’s being expected and what’s indeed written on the wire. And without having the actual content…
One thing you could do would be to aim Gatling at hashicorp/http-echo - Docker Image instead of your AWS service and see if the server is receiving the expected request.
Also, could you please use something like dependencyManagement to downgrade:
- netty from 4.2.10.Final to 4.2.7.Final
- netty-tcnative from 2.0.75.Final to 2.0.74.Final?
With maven, that would give:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>4.2.7.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.2.7.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.2.7.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler-proxy</artifactId>
<version>4.2.7.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns</artifactId>
<version>4.2.7.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<version>4.2.7.Final</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-epoll</artifactId>
<version>4.2.7.Final</version>
<classifier>linux-aarch_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http2</artifactId>
<version>4.2.7.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns-native-macos</artifactId>
<version>4.2.7.Final</version>
<classifier>osx-x86_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns-native-macos</artifactId>
<version>4.2.7.Final</version>
<classifier>osx-aarch_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-classes</artifactId>
<version>2.0.74.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.74.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.74.Final</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.74.Final</version>
<classifier>linux-aarch_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.74.Final</version>
<classifier>osx-x86_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.74.Final</version>
<classifier>osx-aarch_64</classifier>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.74.Final</version>
<classifier>windows-x86_64</classifier>
</dependency>
</dependencies>
</dependencyManagement>
Trying to figure out if the issue comes from us or from Netty.