Making WordPress.org

Opened 7 months ago

Last modified 3 weeks ago

#8201 new defect (bug)

api.wordpress.org fails intermittently with HTTP3/quic

Reported by: samedwards Owned by:
Priority: normal Milestone:
Component: API Keywords:
Cc:

Description

Similar to #7965 (ticket), I'm experiencing intermittent connection errors when connecting to api.wordpress.org. This is mostly from a Composer plugin that's using the Plugin endpoints to check versions. This is using the curl library under the hood

Other users are experiencing the same issue:

It's also reproducible from the command line:

$ curl -v --http3 https://api.wordpress.org/plugins/info/1.0/redirection.json
* Host api.wordpress.org:443 was resolved.
* IPv6: 2607:f978:5:8002::c68f:a4fb
* IPv4: 198.143.164.251
*   Trying [2607:f978:5:8002::c68f:a4fb]:443...
* SSL Trust Anchors:
*   Native: Apple SecTrust
*   OpenSSL default paths (fallback)
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ecPublicKey
* Server certificate:
*   subject: CN=wordpress.org
*   start date: Jan 26 19:43:57 2026 GMT
*   expire date: Apr 26 19:43:56 2026 GMT
*   issuer: C=US; O=Let's Encrypt; CN=E8
*   Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
*   Certificate level 1: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
*   subjectAltName: "api.wordpress.org" matches cert's "*.wordpress.org"
* OpenSSL verify result: 0
* SSL certificate verified via OpenSSL.
* Established connection to api.wordpress.org (2607:f978:5:8002::c68f:a4fb port 443) from 2604:3d08:117d:4c05:45c0:86f4:67ba:72c3 port 58821
* using HTTP/3
* [HTTP/3] [0] OPENED stream for https://api.wordpress.org/plugins/info/1.0/redirection.json
* [HTTP/3] [0] [:method: GET]
* [HTTP/3] [0] [:scheme: https]
* [HTTP/3] [0] [:authority: api.wordpress.org]
* [HTTP/3] [0] [:path: /plugins/info/1.0/redirection.json]
* [HTTP/3] [0] [user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134]
* [HTTP/3] [0] [accept: */*]
> GET /plugins/info/1.0/redirection.json HTTP/3
> Host: api.wordpress.org
> User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134
> Accept: */*
>
* Request completely sent off
* ngtcp2_conn_writev_stream returned error: ERR_DRAINING
* ngtcp2_conn_writev_stream returned error: ERR_DRAINING
* Connection #0 to host api.wordpress.org:443 left intact
curl: (56) ngtcp2_conn_writev_stream returned error: ERR_DRAINING

Change History (1)

#1 @MikeLittle
3 weeks ago

I am hitting the same intermittent errors when using roots/wordpress to pull WordPress into my projects.
It is only intermittent, but it can take three or four retries to clear. Claude gave me all the technical details.

Title: downloads.w.org QUIC/HTTP-3 endpoint accepts connections then immediately closes (ERR_DRAINING), breaking Composer

Summary

downloads.w.org serves fine over HTTP/1.1 and HTTP/2, but its HTTP/3 (QUIC, UDP/443) endpoint completes a TLS handshake, opens an HTTP/3 stream, and then immediately sends a CONNECTION_CLOSE, so any client that attempts HTTP/3 gets a transfer failure (curl error 56 / ngtcp2 ERR_DRAINING). Notably the server also returns alt-svc: clear over HTTP/2, i.e. it signals that HTTP/3 should not be used — yet the QUIC listener is still up and half-answering.

This breaks Composer 2.8.0+, which auto-selects CURL_HTTP_VERSION_3 whenever the local libcurl is built with HTTP/3 support and offers no way to opt out. The result is that composer install/update intermittently fails to download WordPress core zips on any machine with an HTTP/3-capable libcurl (e.g. current Homebrew curl on macOS).

Environment

  • Date observed: 2026-09-18, ~14:45 UTC
  • Host: downloads.w.org → 192.0.77.48, server: nginx, server-timing: a8c-cdn, dc;desc=lhr (London POP)
  • Client: macOS 14.6, curl 8.21.0 (ngtcp2 1.25.0 / nghttp3 1.18.0), Composer 2.10.2, PHP 8.4
  • Client HTTP/3 is otherwise healthy (works fine against Cloudflare and Google in the same session)

Reproduction (plain curl, no Composer needed)
`
# works
curl -sI --http2 ​https://downloads.w.org/release/wordpress-6.8.9-no-content.zip
# → 200, and header: alt-svc: clear
`

`
# fails
curl -sv --http3-only ​https://downloads.w.org/release/wordpress-6.8.9-no-content.zip
# * Established connection ... using HTTP/3
# * [HTTP/3] OPENED stream ...
# * ngtcp2_conn_writev_stream returned error: ERR_DRAINING
# curl: (56) ... ngtcp2_conn_writev_stream returned error: ERR_DRAINING
`

Expected

Either (a) the QUIC/HTTP-3 listener on UDP/443 serves requests correctly, or (b) if HTTP/3 is intentionally disabled (as alt-svc: clear implies), UDP/443 does not accept/negotiate QUIC at all — so clients cleanly fall back to HTTP/2 instead of committing to a connection that is then dropped.

Actual

The QUIC endpoint negotiates TLS 1.3 and opens an HTTP/3 stream, then sends CONNECTION_CLOSE, leaving the client with a failed transfer and no fallback.

Impact

Any WordPress/Altis/Bedrock install using Composer 2.8+ on a host with HTTP/3-enabled libcurl fails to fetch core packages from downloads.w.org. Composer has no flag to disable HTTP/3, so users can only work around it by downgrading Composer or blocking UDP/443.

Note: See TracTickets for help on using tickets.