Flask API Call Intermittently Fails with ERR_HTTP2_PROTOCOL_ERROR

I have a Flask API hosted in Koyeb over the past 4 weeks. I have noticed that the API calls from the frontend site are intermittently getting stuck in the “pending” state and eventually returning a ERR_HTTP2_PROTOCOL_ERROR error. I also tried curling the API endpoint directly and seeing a similar behaviour. When running the Flask app locally, it works just fine. I have even deployed it into an AWS EC2 instance and it works fine.

Bear in mind that the issue is intermittent, if I refresh the page again and again, it can eventually fetch the response successfully.

The error from the browser looks as follows:

Running the API calls manually via Curl:

$ curl 'https://<host>.koyeb.app/<path>' -vvv
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 2606:4700:10::6816:4ebe:443...
* Connected to <host>.koyeb.app (2606:4700:10::6816:4ebe) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
*  CApath: none
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [19 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [2024 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [78 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=*.koyeb.app
*  start date: Sep 15 21:46:41 2024 GMT
*  expire date: Dec 14 21:46:40 2024 GMT
*  subjectAltName: host "<host>.koyeb.app" matched cert's "*.koyeb.app"
*  issuer: C=US; O=Let's Encrypt; CN=E5
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
} [5 bytes data]
* h2h3 [:method: GET]
* h2h3 [:path: <path>]
* h2h3 [:scheme: https]
* h2h3 [:authority: <host>.koyeb.app]
* h2h3 [user-agent: curl/7.83.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x26603890010)
} [5 bytes data]
> GET /<path> HTTP/2
> Host: <host>.koyeb.app
> user-agent: curl/7.83.0
> accept: */*
>
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [230 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [230 bytes data]
* old SSL session ID is stale, removing
{ [5 bytes data]
  0     0    0     0    0     0      0      0 --:--:--  0:01:40 --:--:--     0< HTTP/2 200
< date: Mon, 16 Sep 2024 14:24:15 GMT
< content-type: application/json
< content-length: 21958
< access-control-allow-origin: http://<origin>
< access-control-expose-headers: Content-Type
< vary: Origin
< x-envoy-upstream-service-time: 735
< x-koyeb-backend: par1
< x-koyeb-glb: par1
< cf-cache-status: DYNAMIC
< server: cloudflare
< cf-ray: 8c4182697db85c06-SYD
< alt-svc: h3=":443"; ma=86400
<
{ [5 bytes data]
* HTTP/2 stream 0 was not closed cleanly: INTERNAL_ERROR (err 2)
  0 21958    0     0    0     0      0      0 --:--:--  0:01:41 --:--:--     0
* Connection #0 to host <host>.koyeb.app left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: INTERNAL_ERROR (err 2)

I can see that the Koyeb host is proxied by Cloudflare from the http response headers above. I suspect that the issue might be related to Cloudflare, however there is no related configuration options available for the Koyeb users. I can see that there have been many forum discussions regarding the ERR_HTTP2_PROTOCOL_ERROR issue in the Cloudflare community forums, including this one: https://community.cloudflare.com/t/intermittent-and-random-failed-to-load-resource-net-err-quic-protocol-error/676273

I would appreciate if the Koyeb team looks into this, I have been finding the one-click Flask app deployments extremely valuable, however I have had to opt for an AWS deployment for the time being until we find a solution for this issue.

Also, I have monitored the API logs when the call is made, I can see that it returns the 200 response successfully even while the client is stuck in pending state that leads to the error. So the issue happens between after the Koyeb host sends the response and before the response is received by the client. Given my observation above, having tested the app in Local, AWS and Koyeb, the only culprit seems to be Cloudflare.

Keen for anyone’s inputs on this.

Hey,

As you’ve hidden your app name and path, we assumed that you do not wish to share this information publicly. We reached out privately on Intercom to investigate together :slight_smile: