What happened?
Opening a large progressive HTTP source crashes the app outright — EXC_BREAKPOINT / "Unexpectedly found nil while unwrapping an Optional value" — before a single frame plays. It reproduces on a 12.4 GB MKV; small files are fine.
The crashing thread is a URLSession delegate queue:
0 Foundation Swift runtime failure: Unexpectedly found nil while unwrapping an Optional value
1 Foundation __DataStorage.init(capacity:) + 284
2 Foundation Data._Representation.reserveCapacity(_:) + 644
3 AetherEngine specialized ChunkFetchDelegate.urlSession(_:dataTask:didReceive:completionHandler:) (AVIOReader.swift:2215)
4 CFNetwork __81-[__NSCFURLSessionDelegateWrapper dataTask:didReceiveResponse:completionHandler:]_block_invoke
x0 is 0x0 in the crashed thread's register state — that is malloc returning NULL, and it's the value being force-unwrapped. x19/x2 hold 0x318ffc000 (13,304,315,904 — 12.39 GiB), consistent with the requested capacity being the source's full Content-Length.
The cause is ChunkFetchDelegate.urlSession(_:dataTask:didReceive:completionHandler:):
self.response = response
if let http = response as? HTTPURLResponse {
let len = Int(http.expectedContentLength)
if len > 0 { body.reserveCapacity(len) }
...
}
The reservation is whatever the origin declares, with no ceiling. ChunkFetchDelegate is reached through syncRequest(_:budget:), and one of syncRequest's callers is headProbeFileSize() — a HEAD request. A HEAD response carries Content-Length: <entire file> and delivers zero body bytes, so the delegate asks the allocator for the whole movie in order to buffer nothing. On a 6 GB device a 12.4 GiB malloc fails, and __DataStorage.init(capacity:) force-unwraps the NULL.
Two other threads in the same report were parked in headProbeFileSize() → syncRequest → awaitSignal waiting on exactly that response, which lines up: the source needed the HEAD fallback (the range probes hadn't yielded a length), and the response handler blew up on arrival.
headProbeFileSize() is the clearest trigger, but the same line is reachable from ordinary bounded chunk fetches whenever an origin ignores Range and answers 200 with the full length instead of 206 — the reservation is then the whole file again rather than chunkSize.
Worth noting this is a distinct failure from the gradual memory-exhaustion reports (#31, #220, #243): there's no growth curve and no jetsam here. It's one oversized allocation at open time, and it traps rather than throwing, so a host app can't catch or degrade it.
Steps to reproduce
- Host an MKV large enough that a single
malloc of its byte length fails on the target device (12.4 GB reproduced this on a 6 GB iPhone; an Apple TV's 4 GB should bite lower).
- Serve it from an origin that makes the reader fall back to the HEAD probe — i.e. the
bytes=0- range probes don't resolve a length.
- Open it on the FFmpeg/AVIOReader path.
Crash lands on the URLSession delegate queue as the HEAD response arrives, before playback.
Suggested fix
Cap the reservation, and skip it entirely where no body is coming:
if let http = response as? HTTPURLResponse {
// Size probes (HEAD, and Range GETs that origins answer with the full
// length) declare the whole source while delivering little or no body,
// so the declared length is not a safe reservation.
if dataTask.currentRequest?.httpMethod != "HEAD" {
let len = Int(http.expectedContentLength)
if len > 0 { body.reserveCapacity(min(len, Self.maxBodyReserve)) }
}
...
}
maxBodyReserve at a small multiple of chunkSize would keep the allocation useful for real chunk fetches while making a bogus or whole-file length harmless. Data grows on demand, so the cap costs nothing but a reallocation in the rare case a legitimate body exceeds it.
AetherEngine version or commit SHA
Crash captured on d34e02dd (5.23.7). The line is byte-for-byte identical on 2bfcbd19 (6.0.0) and on 6.1.0, so current main is still affected.
Host app
Custom / my own integration
Platform
iOS
OS version
iOS 26.5.2 (23F84)
Device / chip
iPhone 14 Pro (iPhone15,2), 6 GB RAM
Playback path
FFmpeg / software (custom AVIO)
Source media (for playback bugs)
MKV, ~12.4 GB, over HTTP
What happened?
Opening a large progressive HTTP source crashes the app outright —
EXC_BREAKPOINT/ "Unexpectedly found nil while unwrapping an Optional value" — before a single frame plays. It reproduces on a 12.4 GB MKV; small files are fine.The crashing thread is a URLSession delegate queue:
x0is0x0in the crashed thread's register state — that ismallocreturning NULL, and it's the value being force-unwrapped.x19/x2hold0x318ffc000(13,304,315,904 — 12.39 GiB), consistent with the requested capacity being the source's fullContent-Length.The cause is
ChunkFetchDelegate.urlSession(_:dataTask:didReceive:completionHandler:):The reservation is whatever the origin declares, with no ceiling.
ChunkFetchDelegateis reached throughsyncRequest(_:budget:), and one ofsyncRequest's callers isheadProbeFileSize()— aHEADrequest. AHEADresponse carriesContent-Length: <entire file>and delivers zero body bytes, so the delegate asks the allocator for the whole movie in order to buffer nothing. On a 6 GB device a 12.4 GiBmallocfails, and__DataStorage.init(capacity:)force-unwraps the NULL.Two other threads in the same report were parked in
headProbeFileSize()→syncRequest→awaitSignalwaiting on exactly that response, which lines up: the source needed the HEAD fallback (the range probes hadn't yielded a length), and the response handler blew up on arrival.headProbeFileSize()is the clearest trigger, but the same line is reachable from ordinary bounded chunk fetches whenever an origin ignoresRangeand answers200with the full length instead of206— the reservation is then the whole file again rather thanchunkSize.Worth noting this is a distinct failure from the gradual memory-exhaustion reports (#31, #220, #243): there's no growth curve and no jetsam here. It's one oversized allocation at open time, and it traps rather than throwing, so a host app can't catch or degrade it.
Steps to reproduce
mallocof its byte length fails on the target device (12.4 GB reproduced this on a 6 GB iPhone; an Apple TV's 4 GB should bite lower).bytes=0-range probes don't resolve a length.Crash lands on the URLSession delegate queue as the HEAD response arrives, before playback.
Suggested fix
Cap the reservation, and skip it entirely where no body is coming:
maxBodyReserveat a small multiple ofchunkSizewould keep the allocation useful for real chunk fetches while making a bogus or whole-file length harmless.Datagrows on demand, so the cap costs nothing but a reallocation in the rare case a legitimate body exceeds it.AetherEngine version or commit SHA
Crash captured on
d34e02dd(5.23.7). The line is byte-for-byte identical on2bfcbd19(6.0.0) and on6.1.0, so currentmainis still affected.Host app
Custom / my own integration
Platform
iOS
OS version
iOS 26.5.2 (23F84)
Device / chip
iPhone 14 Pro (iPhone15,2), 6 GB RAM
Playback path
FFmpeg / software (custom AVIO)
Source media (for playback bugs)
MKV, ~12.4 GB, over HTTP