ARC download of ALAC track crashes RoonServer during sync (ref#EYBSI6) [Ticket in]

Hi! What’s not quite right with Roon?

· None of the above quite fits

None of the above quite fits

· None of these quite match

Tell us what's going on

· # ARC/offline download of one decoder-rejected ALAC track repeatedly terminates the entire RoonServer process

**Severity:** High — all playback and connected clients are interrupted; the crash repeats when mobile sync retries.

## Summary

·
Reconnecting a mobile/ARC client so that an offline album download could continue caused RoonServer to terminate three times. Each termination occurred while Roon's mobile download service was transcoding the same local ALAC track at `LossyHigh` quality. The fatal exception is an unhandled `Roon.Audio.CorruptMediaException` in `Sooloos.Broker.Mobile.ETDPDownloadOpus.WorkerMethod()`.

The source file may genuinely be damaged or otherwise rejected by Roon's decoder. The bug is that failure of one background mobile download escapes its worker and terminates the entire RoonServer process. The service supervisor restarts RoonServer, but mobile sync later retries the item and can crash it again.

## Environment

·
- RoonServer 2.70 (build 1671), production, linuxx64
- RoonOS 2.1 (build 271), production
- Source: local ALAC, 16-bit/44.1 kHz, `.m4a`
- ARC/offline download quality: `LossyHigh`
- Offending item reported by Roon: `Portico Quartet / Isla / 07 - Life Mask.m4a`
- Normal audio playback was active during the first incident.

## Steps that triggered the fault

·
1. Configure a mobile/ARC client to download the album *Isla* for offline use.
2. Disconnect the client before the download completes.
3. Reconnect it so mobile sync resumes.
4. Roon logs `RespondDownload` and starts transcoding `07 - Life Mask.m4a`.
5. The Opus-download worker throws `Roon.Audio.CorruptMediaException` and the entire RoonServer process terminates.
6. RoonServer automatically restarts. When mobile sync retries the track, the process can terminate again.

## Expected result

·
Roon should mark the one track/download as failed, report the media error to the client, and keep RoonServer and unrelated playback running.

## Actual result

·
The exception is unhandled on the mobile-download worker thread and terminates RoonServer. All zones, clients, and extensions lose the Core until its supervisor restarts it.

## Repeated occurrences

·
| Crash (UTC) | Crash (EDT) | Next RoonServer start (UTC) | Result |
|---|---|---|---|
| 2026-08-03 21:37:40 | 17:37:40 | 21:37:42 | Same exception and mobile-worker stack |
| 2026-08-03 21:42:13 | 17:42:13 | 21:42:15 | Same exception and mobile-worker stack |
| 2026-08-03 22:11:40 | 18:11:40 | 22:11:42 | Same exception and mobile-worker stack |

This is process termination, not merely a client disconnect: each pre-crash log ends with the exception report, and the following log begins with `Starting RoonServer v2.70 (build 1671)` two seconds later.

## Crash signature

·
```text
Exception Source: Roon.Media
Exception Type: Roon.Audio.CorruptMediaException
Exception Target Site: MediaDecoderStream.ReadImp
Exception Message: Got CorruptFile while reading from stream

Roon.Audio.MediaDecoderStream.ReadImp(...)
Roon.Audio.AudioStream.Read(...)
Roon.Audio.PCMToFloatStream.ReadImp(...)
Roon.Audio.PolyphaseResamplerStream.ReadImp(...)
Roon.Audio.ConvertBitDepthStream.ReadImp(...)
Sooloos.Broker.Mobile.ETDPDownloadOpus.FeedEncoder(...)
Sooloos.Broker.Mobile.ETDPDownloadOpus.WorkerMethod()
System.Threading.Thread/StartHelper.Callback(...)
```

## Why this appears isolated to ARC/mobile sync

·
- Immediately before each exception, the log identifies the `[mobile] [Mobile] RespondDownload` path.
- The fatal stack terminates in `ETDPDownloadOpus.WorkerMethod`, not an active playback-zone encoder.
- The same album and track are retried after each automatic RoonServer restart.
- The first crash occurred during unrelated, healthy playback; the playback stream was not the file named by the fatal worker. ## Root cause of the source-file defect (established 2026-08-04)

The source file is genuinely malformed, and Roon’s decoder is correct to reject it. The defect is in the MP4
container structure, not the audio payload.

Walking the root-level atom chain of the offending file:

  @         0  ftyp  size=        32
  @        32  moov  size=     25296  end=25328
  @     25328  <non-ASCII>  size=3098241624   <-- extends 3,058,711,518 bytes past EOF

There is no mdat atom. Where the audio container header should begin, the bytes do not form a valid atom: the
type field is non-ASCII and the declared size (about 3.1 GB) exceeds the 39,555,434-byte file by roughly 3 GB.

Two known-good tracks from the same album and the same encoder show the expected structure:

05 - Life Mask Interlude:  ftyp(32) -> moov(43059) -> free(56954) -> mdat(4932283)
08 - Isla:                 ftyp(32) -> moov(55189) -> free(57113) -> mdat(32713295)

So free and the mdat header are absent in the offending file; the raw audio payload begins immediately after
moov with no container header.

The audio itself is intact. All 4,692 ALAC packets decode without error, yielding 435.75 s — exactly matching the
435,750ms Roon reports in [transcodestream]. Decoded-PCM MD5 is fb344b9153748d5e471e40b37f3c9e61.

Why other players do not fail. FFmpeg locates samples through the stco chunk-offset table in moov, which
holds absolute file offsets, so it never walks the root atom chain and never encounters the malformed header. It
decodes the file cleanly even with -err_detect +crccheck+bitstream+buffer. A decoder that validates container
structure — as Roon’s evidently does — reaches the bad atom and correctly raises CorruptFile. This explains why the
file appears healthy in most tools yet reliably terminates RoonServer.

Lossless repair. Remuxing with ffmpeg -i in.m4a -map 0:a -c:a copy -movflags +faststart out.m4a rebuilds a valid
ftyp -> moov -> free -> mdat chain and reproduces decoded-PCM MD5 fb344b9153748d5e471e40b37f3c9e61 — bit-identical
audio, valid container. Tags (title, artist, album, track) are preserved.

This narrows the report rather than weakening it. Roon is right to reject the file. The defect is solely that an
expected, recoverable media error on a background mobile-download worker escapes that worker and terminates the entire
RoonServer process. A malformed file anywhere in a library should not be able to crash the Core.

- Recent resource statistics showed ample memory and no out-of-memory exception. For example, immediately before the first crash Roon reported about 2.9 GB physical use, 542 handles, and 94 threads.

# Redacted evidence excerpts

·
Sensitive identifiers from the raw logs have been omitted: user ID, device serial, Core ID, public IP, client connection identifiers, and local host addresses. The library root and internal track IDs are also shortened below. The timestamps, media name, exception type, and decisive stack frames are unchanged.

## Crash 1 — 21:37:40 UTC / 17:37:40 EDT

·
text<br>08/03 21:37:35 [Local 08/03 17:37:35] Trace: [playback zone] [100% buf] [PLAYING @ 0:25/1:07] [unrelated active track]<br>08/03 21:37:39 [Local 08/03 17:37:39] Trace: [mobile] [Mobile] RespondDownload <track-id>, LossyHigh --> <library>/Portico Quartet/Isla/Portico Quartet - Isla - 05 - Life Mask Interlude.m4a<br>08/03 21:37:40 [Local 08/03 17:37:40] Trace: [mobile] [Mobile] RespondDownload <track-id>, LossyHigh --> <library>/Portico Quartet/Isla/Portico Quartet - Isla - 07 - Life Mask.m4a<br>08/03 21:37:40 [Local 08/03 17:37:40] Info: [transcodestream] transcoding <library>/Portico Quartet/Isla/Portico Quartet - Isla - 07 - Life Mask.m4a from StreamFormat(channels=2, bitspersample=16, samplerate=44100, isdts=False) to StreamFormat(channels=2, bitspersample=24, samplerate=48000, isdts=False) (435,750ms)<br>08/03 21:37:40 [Local 08/03 17:37:40] Info:<br> Exception Source: Roon.Media<br> Exception Type: Roon.Audio.CorruptMediaException<br> Exception Target Site: MediaDecoderStream.ReadImp<br> Exception Message: Got CorruptFile while reading from stream<br> ...<br> Sooloos.Broker.Mobile.ETDPDownloadOpus.FeedEncoder(...)<br> Sooloos.Broker.Mobile.ETDPDownloadOpus.WorkerMethod()<br><br>08/03 21:37:42 Info: Starting RoonServer v2.70 (build 1671) production on linuxx64<br>

## Crash 2 — 21:42:13 UTC / 17:42:13 EDT

·
text<br>08/03 21:42:08 [Local 08/03 17:42:08] Trace: [mobile] [Mobile] RespondDownload <track-id>, LossyHigh --> <library>/Portico Quartet/Isla/Portico Quartet - Isla - 05 - Life Mask Interlude.m4a<br>08/03 21:42:12 [Local 08/03 17:42:12] Trace: [mobile] [Mobile] RespondDownload <track-id>, LossyHigh --> <library>/Portico Quartet/Isla/Portico Quartet - Isla - 07 - Life Mask.m4a<br>08/03 21:42:12 [Local 08/03 17:42:12] Info: [transcodestream] transcoding <library>/Portico Quartet/Isla/Portico Quartet - Isla - 07 - Life Mask.m4a from StreamFormat(channels=2, bitspersample=16, samplerate=44100, isdts=False) to StreamFormat(channels=2, bitspersample=24, samplerate=48000, isdts=False) (435,750ms)<br>08/03 21:42:13 [Local 08/03 17:42:13] Info:<br> Exception Type: Roon.Audio.CorruptMediaException<br> Exception Message: Got CorruptFile while reading from stream<br> ...<br> Sooloos.Broker.Mobile.ETDPDownloadOpus.WorkerMethod()<br><br>08/03 21:42:15 Info: Starting RoonServer v2.70 (build 1671) production on linuxx64<br>

## Crash 3 — 22:11:40 UTC / 18:11:40 EDT

·
text<br>08/03 22:11:32 [Local 08/03 18:11:32] Info: [stats] 22098mb Virtual; 1342mb Physical; 513 Handles; 91 Threads<br>08/03 22:11:39 [Local 08/03 18:11:39] Trace: [library/mobilesync] Downloading <album-id> LibraryAlbum[<id>, Portico Quartet - Isla] ...<br>08/03 22:11:40 [Local 08/03 18:11:40] Trace: [mobile] [Mobile] RespondDownload <track-id>, LossyHigh --> <library>/Portico Quartet/Isla/Portico Quartet - Isla - 07 - Life Mask.m4a<br>08/03 22:11:40 [Local 08/03 18:11:40] Info: [transcodestream] transcoding <library>/Portico Quartet/Isla/Portico Quartet - Isla - 07 - Life Mask.m4a from StreamFormat(channels=2, bitspersample=16, samplerate=44100, isdts=False) to StreamFormat(channels=2, bitspersample=24, samplerate=48000, isdts=False) (435,750ms)<br>08/03 22:11:40 [Local 08/03 18:11:40] Info:<br> Exception Type: Roon.Audio.CorruptMediaException<br> Exception Message: Got CorruptFile while reading from stream<br> ...<br> Sooloos.Broker.Mobile.ETDPDownloadOpus.WorkerMethod()<br><br>08/03 22:11:42 Info: Starting RoonServer v2.70 (build 1671) production on linuxx64<br>

# Evidence provenance

·
The source logs were copied read-only from the RoonServer Data/RoonServer/Logs share immediately after the third incident. Raw logs are intentionally not included in this report because they contain private account, device, network, and library information.

| Raw Roon log | SHA-256 |
|—|—|
| RoonServer_log.03.txt | 931f4bdbe71d68a20e38d57b70d9cbb77aa45324024e44b682e94602d0ac8e9d |
| RoonServer_log.02.txt | 39e5f9801b7b2d3b5a2fb821ec94c191341e1f9bb4912fcfbfe14ddc0a5f3be6 |
| RoonServer_log.01.txt | f5d0d2684cd6895eb562814fd71415860cea287cb7de31e2ce6f36756a48d94e |
| RoonServer_log.txt after restart | d6ad860e098e8191a3f76f09d553586f3b03c01acd814148c79edb4225cf1805 |

Tell us about your home network

· Unifi Dream maxhine and Unifi switches

Hey @peter_richardson, welcome to the community.

This is a useful report, and the stack trace does point to the mobile download path rather than normal zone playback.

Because the file itself is being rejected as corrupt, the most likely next step is to confirm whether this happens with that specific track only or whether any other local file will trigger the same behavior during ARC download.

With that, can you please update all your Roon devices to the latest version and see if you still experience the issue?

Thank you :+1:

Thanks Benjamin. All my devices are current. (Just saw you issued an update a very short while ago :slightly_smiling_face:). Only the corrupt file seems to trigger this - it wont be an issue for me in the future but may stop downloads and cause frustration to anyone else seeing this on their system and not being able to modify the files. Don’t think I need to keep triggering it!

Hello @peter_richardson

It might be helpful to have the file(s) for testing on our end as well, can please upload them here and let us know?

https://workdrive.zohoexternal.com/collection/nqcgjac23027d90a441bda2c314de49d7958a/external

Yes, I had saved a copy.

The requested RoonServer logs have now been uploaded to your Media Uploader

roon-ref-EYBSI6-roonserver-logs-20260803.zip (1.2 MB)

These correspond to the CorruptMediaException crashes described in my report:

Happy to provide the offending media file or anything else you need. Hope this helps.

Thanks,

Peter

PS Since fixing this I am now able to enjoy many more downloaded albums to my phoe - could never work out why it always failed to smart-download much for me! Always thought it just wasn’t that smart :wink:

Hi @peter_richardson

Thanks, though we were after the audio file itself rather than the logs. The logs are useful to have, so no harm done, but what our developers need is the actual track that triggers the CorruptMediaException, so they can reproduce it here.

Please upload the offending file to the same link, and tell us its filename and where it sits in your library so we can line it up with the crashes in your logs.

https://workdrive.zohoexternal.com/collection/nqcgjac23027d90a441bda2c314de49d7958a/external

If there was more than one file involved, please send them all.

And your PS is the useful part of this whole report. A single unreadable file quietly stopping ARC from downloading the rest is exactly the kind of thing people would never connect to a corrupt track, so thank you for working it out and telling us.

2026-08-11

Hi,

The offending file is now uploaded to the same Media Uploader link, under the

uploader name “Peter Richardson — ref#EYBSI6”:

Portico Quartet - Isla - 07 - Life Mask.m4a (39,555,434 bytes, MD5 b49c7d7bd5d5010b3718a9b3fd6f0d1e)

This is the untouched original — not remuxed or repaired. Your uploader’s MD5

matched mine after transfer, so what you have is bit-identical to the file here.

Where it sits in my library — the exact path from the logs I sent:

/roon/sys/storage/mounts/InternalStorage/NAS Library/Portico Quartet/Isla/Portico Quartet - Isla - 07 - Life Mask.m4a

That path appears in the RespondDownload / transcodestream lines immediately

before each of the three crashes.

It was the only file involved: all three crashes reference this one track, and

I’ve since checked every other file on the album — the rest are structurally

healthy.

In case it saves your developers a step: the container’s root atom chain is

ftyp(32) → moov(25296), then at offset 25328 a malformed atom with a non-ASCII

type and a declared size of ~3.0 GB (far past the 39.5 MB end of file) — and no

mdat atom at all. Tools that seek audio via the stco chunk-offset table (ffmpeg,

most players) decode it perfectly, which is how it sat undetected in the library

for years; anything that validates container structure while reading hits the

malformed atom, which lines up with the CorruptMediaException in the logs. A

plain remux (ffmpeg -c:a copy) yields a valid file with bit-identical decoded

PCM, so the audio itself is intact — it’s purely a container defect.

Glad the ARC-queue observation was useful.

Thanks,

Peter Richardson

Thanks for the thoroughness here @peter_richardson! We’ve shared all your findings with development for further investigation. :raising_hands:

Thanks Ben. This is where judicious use of AI tools really pays off . Certainly I wouldn’t have been able to put together as a coherent assessment and provide well organized material without it. :wink:

Hello @peter_richardson

Thanks Peter. Your report and the file are now logged with development as a ticket, and the crash itself is what they will be looking at.

Nothing further is needed from you. Your remux has already sorted the file at your end, so we will close this thread here. If ARC downloads start misbehaving again, please open a new one with a link back to this thread.

Please follow our Roon Software Discussion > Software Release Notes for the fix