Media: 3.7 GB H.264 (avc1.640033, 3840x1920) + AAC MKV, VOD, served by an Xtream-style aggregator with max_connections=1, 302→http redirects, and no suffix-range support. Apple TV 4K, tvOS 26. AetherEngine 6.7.0, native dispatch path.
Symptom: Playback freezes ~1 min in, then dies. The log shows the reader wedged at a 32 MiB range frontier, reconnecting ~15×/s with zero backoff — 925 reconnects in 60 s — until the segment provider's forward-wait escalation tears the demuxer down (demuxer.readPacket threw: read failed (-1) → pump finished: reason=readError(-1)), after which the session is unrecoverable:
[AVIOReader] pump conn start gen=5 offset=131554695 len=32MB
[AVIOReader] pump conn gen=5 ended with error: cancelled
[AVIOReader] pump conn start gen=6 offset=131554695 len=32MB
[AVIOReader] pump conn gen=6 ended with error: cancelled
... (925 generations, same offset) ...
[AVIOReader] slow read: 60012ms at offset=131554695 detour=0(0ms,0fetch)
stallWaits=925(59365ms,925signaled) reconnects=925 backoff=0ms gen=5->931
[HLSSegmentProducer] pump finished: reason=readError(-1)
Root cause (three stacked defects):
- A connection that ends in error with zero bytes delivered for its generation lands in the no-connection reposition branch (
AVIOReader.swift readPersistent, the activeTask == nil, !connEndedByBackpressure, !windowCanServe guard). That branch reconnects via seekReconnect, which resets unproductiveReconnects and applies no backoff, so the ended-connection ladder (status accounting, Retry-After, backoff, .reconnecting, bounded give-up) is unreachable. The spiral is unbounded by design.
- The rejected response's status is never logged (only the 200-ignored-Range case is), so the storm is unexplained in the field log.
- The pinned post-redirect URL is only invalidated on 401/403/404/410. An aggregator whose redirect targets expire per connection answers every later range with a hard 500 from the pinned URL, and the reader never falls back to the source URL for a fresh redirect.
Bonus: once the pump dies, handleVODReadErrorExit's revive cap (#169) exhausts silently — onVODSourceFailed is only fired from the produced-nothing arm, so the host sees a forever-stalled AVPlayer with no error.
Repro: loopback origin that 302-redirects to a "CDN" which serves the first bounded range and answers 500 for every request at the next frontier (deterministic repro used for the tests in the linked PR; also reproduced with aetherctl play against such an origin).
Expected: an error-ended zero-byte connection takes the failure ladder (backoff, bounded give-up), a hard 5xx from a pinned URL drops the pin and re-resolves through the source URL, and revive-cap exhaustion surfaces onVODSourceFailed.
PR with fix + tests follows.
Media: 3.7 GB H.264 (avc1.640033, 3840x1920) + AAC MKV, VOD, served by an Xtream-style aggregator with
max_connections=1,302→httpredirects, and no suffix-range support. Apple TV 4K, tvOS 26. AetherEngine 6.7.0, native dispatch path.Symptom: Playback freezes ~1 min in, then dies. The log shows the reader wedged at a 32 MiB range frontier, reconnecting ~15×/s with zero backoff — 925 reconnects in 60 s — until the segment provider's forward-wait escalation tears the demuxer down (
demuxer.readPacket threw: read failed (-1)→pump finished: reason=readError(-1)), after which the session is unrecoverable:Root cause (three stacked defects):
AVIOReader.swiftreadPersistent, theactiveTask == nil, !connEndedByBackpressure, !windowCanServeguard). That branch reconnects viaseekReconnect, which resetsunproductiveReconnectsand applies no backoff, so the ended-connection ladder (status accounting, Retry-After, backoff,.reconnecting, bounded give-up) is unreachable. The spiral is unbounded by design.Bonus: once the pump dies,
handleVODReadErrorExit's revive cap (#169) exhausts silently —onVODSourceFailedis only fired from the produced-nothing arm, so the host sees a forever-stalled AVPlayer with no error.Repro: loopback origin that 302-redirects to a "CDN" which serves the first bounded range and answers 500 for every request at the next frontier (deterministic repro used for the tests in the linked PR; also reproduced with
aetherctl playagainst such an origin).Expected: an error-ended zero-byte connection takes the failure ladder (backoff, bounded give-up), a hard 5xx from a pinned URL drops the pin and re-resolves through the source URL, and revive-cap exhaustion surfaces
onVODSourceFailed.PR with fix + tests follows.