[Django]-Getting "curl: (92) HTTP/2 stream 1 was not closed cleanly: INTERNAL_ERROR (err 2)"

29πŸ‘

I got the same error with an application behind an AWS Application Load Balancer, using command:

curl "https://console.aws.example/api/xxx" -b "SESSION=$SESSION"
                                                                         

15:14:30 curl: (92) HTTP/2 stream 1 was not closed cleanly:
PROTOCOL_ERROR (err 1)

I had to force the use of HTTP/1.1 with the argument --http1.1

So the final command is:

curl "https://console.aws.example/api/xxx" -b "SESSION=$SESSION" --http1.1
πŸ‘€veben

16πŸ‘

I had this issue with AWS’s Application Load Balancer (ALB). The problem was that I had Apache configured to use http2, but behind an ALB. The ALB supports http2 by default:

Application Load Balancers provide native support for HTTP/2 with HTTPS listeners. You can send up to 128 requests in parallel using one HTTP/2 connection. The load balancer converts these to individual HTTP/1.1 requests and distributes them across the healthy targets in the target group. Because HTTP/2 uses front-end connections more efficiently, you might notice fewer connections between clients and the load balancer. You can’t use the server-push feature of HTTP/2. 1

So, curl was using HTTP/2 to connect with the ALB, which was then converting it into an HTTP/1 request. Apache was adding headers to the response asking the client to Upgrade to HTTP/2, which the ALB just passed back to the client, and curl read it as invalid since it was already using an HTTP/2 connection. I solved the problem by disabling HTTP/2 on my Apache instance. Since it will always be behind an ALB, and the ALB is never going to make use of HTTP/2, then there is no point of having it.

πŸ‘€lightswitch05

9πŸ‘

Fix or Remove the Content-Length header in your HTTP request.

I was trying to connect to an AWS Gateway when this issue occurred to me. I was able to get the correct response using POSTMAN but if I copied over the same headers to curl, it would give me this error.

What finally worked for me was removing the Content-Length header as the length of the request in curl wasn’t matching the same as it was in POSTMAN.

Since in my case I was only testing the API so this is fine, but I wouldn’t suggest removing this header in production. Check to make sure the length is calculated correctly if this is occurring to you in a codebase.

1πŸ‘

With Nginx, you can experience this error in curl by having two http2 virtual hosts listening on the same server name. Running a check on your nginx config file will throw a warning letting you know that something isn’t right. Fixing/removing the duplicate listing fixes this problem.

# nginx -t
nginx: [warn] conflicting server name "example.com" on 0.0.0.0:443, ignored
nginx: [warn] conflicting server name "example.com" on [::]:443, ignored
πŸ‘€jaywilliams

0πŸ‘

On my side issue was in the response header "Upgrade"=h2,h2c.
For example, extended response from curl -v:

* http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [upgrade], value: [h2,h2c]
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* stopped the pause stream!

I set this header empty Upgrade: "" and curl on http2 started working correctly.

0πŸ‘

For me what solved it was to set ssl sec level to 1.
See CURLOPT_SSL_CIPHER_LIST

πŸ‘€Nir

Leave a comment