We're seeing what looks like the same behavior on the production endpoint.
Our timeline matches yours exactly and is still on going as of this post:
- First occurrences: 2026-07-29, ~19:13 UTC (low rate, a few per hour)
- Sharp increase: 2026-08-03, ~19:00 UTC (~4/hour to ~300/hour within one hour, still ongoing)
Stack: PHP 8.2 / libcurl 8.17.0 / nghttp2 1.59.0 (edamov/pushok), HTTP/2 with token-based auth, AWS us-east-1.
Symptom: connections to api.push.apple.com terminate before any HTTP response arrives (libcurl reports HTTP code 0). The error string varies by where in the exchange it dies: Error in the HTTP2 framing layer, Send failure: Connection reset by peer, Recv failure: Connection reset by peer, OpenSSL SSL_read: ... unexpected eof while reading, Send failure: Broken pipe.
Packet capture
We enabled VPC flow logs with TCP flags recorded. The RSTs originate from the APNs edge addresses themselves (RST bit set on ingress flows whose source is 17.188.x). There is no NAT, proxy, or stateful firewall in our path.
The failures partition cleanly by edge prefix. Over ~10 hours on 2026-08-04:
APNs edge prefixConnectionsReset by peerRate
17.188.143.x, 17.188.178.x, 17.188.179.x | 1,136 | 941 | 83% |
17.188.169–172.x, 17.188.180–183.x | 2,502 | 1 | 0.04% |
That's all from the same four hosts, in the same minutes, all on port 443. We hit 197 distinct edge addresses in that window and they were all either fine or broken, with nothing in between, which is what made us start looking at the prefixes in the first place. DNS hands back a rotating mix of the two groups, so our hourly failure rate ends up being mostly a function of how many addresses in a given answer happen to be from the broken set. For us that's averaged around 30%.
The two cases also look different at the packet level. Connections that work get closed by the edge with a FIN, as you'd expect. The ones that fail get an RST instead, and not at setup: one we captured had already carried 49,348 bytes over 103 packets before it died.
As of 2026-08-04 ~18:15 UTC, addresses in the second group began resetting as well (0% → ~50% over the following 90 minutes), which is consistent with a staged rollout of whatever changed.
Unauthenticated probes to the failing prefixes succeed normally — TLS and HTTP/2 negotiate, and both single and 20-stream multiplexed requests return expected status codes. Whatever triggers the reset appears to require an authenticated push request.
Ruled out on our side: no deploy or configuration change at onset; send volume that day was below our two-week average, no correlation with BadDeviceToken, unrestricted egress with no NAT; four hosts across two availability zones with four different public IPs show identical reset rates.
Happy to provide exact UTC timestamps, flow log exports, per-prefix breakdowns, or source addresses privately.