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:
- https://github.com/inpsyde/wp-translation-downloader/issues/43
- https://github.com/typisttech/wp-org-closed-plugin/pull/22
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
Note:
See TracTickets
for help on using tickets.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
I am hitting the same intermittent errors when using
roots/wordpressto 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.orgserves 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 returnsalt-svc: clearover 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_3whenever the locallibcurlis built with HTTP/3 support and offers no way to opt out. The result is thatcomposer install/updateintermittently fails to download WordPress core zips on any machine with an HTTP/3-capable libcurl (e.g. current Homebrew curl on macOS).Environment
downloads.w.org→ 192.0.77.48,server: nginx, server-timing: a8c-cdn, dc;desc=lhr(London POP)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: clearimplies), 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.