APNs sandbox: Has HTTP/2 request-rejection behavior changed?

Beginning July 29, 2026, we noticed a higher number of error responses from api.sandbox.push.apple.com:

http2: server sent GOAWAY and closed the connection;
LastStreamID=2147483647;
ErrCode=PROTOCOL_ERROR;
debug="Stream 3 does not exist for inbound frame DATA, endOfStream = true"

The errors:

  • Occur across multiple independent applications and regions.
  • Are concentrated on the APNs sandbox endpoint.
  • Did not coincide with a deployment or configuration change in our service.
  • Were not accompanied by other typical failures such as 400 BadDeviceToken.
  • Also increased on the APNs production endpoint, though the large majority remain concentrated on the sandbox endpoint.

Could Apple confirm whether APNs recently changed how notification requests are validated or rejected, particularly in the sandbox environment?

We can provide exact UTC timestamps, source regions, request metadata, and logs privately if needed.

FYI Starting from yesterday (2026-08-03) we are seeing this behavior in non-sandbox as well.

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.x1,13694183%
17.188.169–172.x, 17.188.180–183.x2,50210.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.

APNs HTTP/2 gateways abruptly closing connections — RST frames, GOAWAY PROTOCOL_ERROR frames and TCP socket resets — beginning around 2026-08-03 19:00 UTC and affecting all geographies

The issue is visible globally, world wide

Update: we found what triggers this, and worked around it.

Short version, it's the number of requests you have in flight on a single connection at the same time. We were multiplexing 20 pushes onto one connection, which is the pushok library's default. Dropping that to one request at a time made the problem go away entirely.

I also need to correct something from my earlier post. I made a lot of the split between address ranges, and that turned out to be misleading. When we tested directly against the ranges that looked clean in our traffic, they failed too, as long as we sent 20 requests at once. The reason those ranges looked healthy is that most of our pushes go out in small batches, small enough to get through. So the address ranges were never really the issue. Batch size was, and the prefix pattern was just a side effect of which traffic happened to land where.

Here's the test we ran. We sent 20 pushes with deliberately invalid device tokens, so nothing could actually be delivered, against several different APNs IPs. The only thing we changed between runs was the concurrency:

  • 20 requests multiplexed onto 1 connection: failed 9 out of 9 times
  • 5 requests per connection: worked 7 out of 8 times
  • 1 request per connection: worked 9 out of 9 times

Leaving the connection open between batches made no difference at all, so it isn't about connection reuse or how old the connection is.

The change we shipped was setting concurrent requests to 1 and concurrent connections to 5 on our APNs client library.

Before the deploy we were failing 85-90% of pushes. Within about twenty minutes of it going out we were at zero, and our push volume is back to what it was before any of this started. It costs us roughly half a second per job, which is a trade we're happy with.

If you're on a different HTTP/2 client, look for whatever controls how many requests share a connection.

One last note on the rollout. By late on the 4th, nearly every address range we touch was affected, not just the ones I listed earlier. So if you tested a while back and concluded some servers were fine, that may not hold anymore.

There was an apple rolling out a version which triggered this behaviour, they rolled it back

APNs sandbox: Has HTTP/2 request-rejection behavior changed?
 
 
Q