MusicAnalysis Decodes Entire Multi-Disc Box Set Simultaneously, Exhausting Container Memory

Summary

When Plex performs loudness analysis on a large multi-disc box set, the Butler MusicAnalysis task decodes all tracks simultaneously into /tmp as PCM WAV files before running the analyser. On a 55-disc box set (665 tracks), this generates approximately 16 GB of temporary data, exhausting available RAM and swap and causing an OOM crash of the entire Plex container.


Environment

  • Plex Media Server: v1.43.2.10687-563d026ea
  • OS: Debian GNU/Linux (trixie), LXC container on Proxmox VE
  • Container RAM: 8 GB (cgroup hard limit)
  • Swap: 8 GB
  • CPU: Intel Core i5-14400 (4 vCPUs assigned)

Steps To Reproduce

  1. Add a large multi-disc classical box set to a Plex music library where the discs are grouped as a single album entity (e.g. a 55-disc collection)
  2. Enable loudness analysis in Butler scheduled tasks
  3. Wait for Butler to run (default 2:00–5:00 AM window)
  4. Butler MusicAnalysis triggers on the box set

Observed Behaviour

Butler MusicAnalysis queues all 665 tracks of the box set as a single analysis job and begins decoding every track simultaneously into /tmp using Plex Transcoder with the following ffmpeg command per track:

"Plex Transcoder" -i <track.flac> -ac 1 -ar 16000 -acodec pcm_s16le track-NNNN.wav

All decoded WAV files accumulate in a single temporary directory:

/tmp/music-analysis-input-<uuid>/

With 665 tracks at approximately 24 MB each (16kHz mono PCM, ~13 min average classical track length), this generates ~16 GB of temporary data before the analyser processes it.

This exhausts both container RAM (8 GB) and swap (8 GB), triggering the Linux OOM killer and crashing Plex. The container becomes completely unresponsive (load 12–17, all processes in D-state) and requires a full restart to recover.


Log Evidence

From Plex Media Server.log at the point of failure:

Jun 25, 2026 02:05:13  [Butler/MusicAnalysis] Decoding 665 files for input to the analyzer.
Jun 25, 2026 02:05:39  [Butler/MusicAnalysis/JobRunner] Job running: ... -i "Disc 15/.../track.flac" -ac 1 -ar 16000 -acodec pcm_s16le track-0139.wav
Jun 25, 2026 02:06:15  [Butler/MusicAnalysis/JobRunner] Job running: ... -i "Disc 32/.../track.flac" -ac 1 -ar 16000 -acodec pcm_s16le track-0330.wav
...
Jun 25, 2026 02:06:48  WARN - Held transaction for too long: 8.07 seconds
Jun 25, 2026 02:07:00  WARN - SLOW QUERY: 5450ms
Jun 25, 2026 02:16:31  [last log entry — system frozen]
Jun 25, 2026 02:18:45  [Plex restarts] SQLITE3: recovered 348 frames from WAL file

cgroup memory events at time of crash:

high        108,688,694   (soft limit crossed 108 million times)
max             558,476   (hard limit hit 558,476 times)
oom                  16
oom_kill              2

Root Cause

The MusicAnalysis pipeline does not need all tracks decoded simultaneously to calculate album gain. EBU R128 album gain is a statistical aggregate of per-track loudness measurements — each track can be measured independently and the results accumulated, with album gain calculated from the stored values at the end.

Tools such as loudgain, foobar2000, and beets all implement this correctly: one track decoded at a time, measurement stored, WAV discarded, next track processed. Peak working set is a single decoded track regardless of album size.

Plex’s current implementation appears to have been designed with the Redbook CD limit of 99 tracks as an implicit assumption, making the worst-case /tmp footprint approximately 2.4 GB — acceptable on most systems. Multi-disc box sets grouped as a single Plex album entity break this assumption, with no upper bound on the number of tracks that can be queued as a single job.


Impact

  • Full container/server OOM crash requiring manual restart
  • Occurs every night during the Butler window until all tracks are processed
  • Since Plex restarts before completing the job, analysis never finishes — the crash loop is permanent until the library configuration is changed
  • SQLite WAL data loss on each crash (348–431 frames recovered on restart)
  • Affects any user with a large multi-disc box set grouped as a single album, particularly classical music collections

Expected Behaviour

Butler MusicAnalysis should process tracks in bounded batches — decoding one track at a time (or a small fixed number in parallel), storing the per-track loudness measurement, discarding the WAV, then aggregating album gain from the stored values once all tracks are measured. Peak /tmp usage should be proportional to batch size, not total album track count.

A safe batch size cap of 99 tracks would align with the Redbook physical limit and prevent this class of issue entirely for any real-world album or box set.


Workaround

Mount /tmp inside the Plex container on a disk-backed filesystem rather than the default RAM-backed tmpfs, providing sufficient space for the full decoded working set without consuming container RAM.

Why is /tmp using memory?

This is not recommended.

yes as I mentioned one workaround would be to attach tmp on a disk. Still the workflow is problematic though unless there is some other reason of trying to decode all files first and then start to analyze them.