A Plex server with 90 days of uptime, a green service status, and perfectly working H.264 playback can still fail every single EAC3 transcode with a generic "Conversion failed" error. Nothing about Plex changed. No update, no config edit, no disk full. A systemd timer quietly deleted the transcoder's scratch directory out from under it, and Plex has no idea.
This one is worth understanding if you run Plex on any systemd-based Linux, whether that's bare metal, a VM, or an unprivileged LXC on Proxmox. It's especially relevant right now because Debian 13 enabled automatic /tmp cleaning by default, so setups that ran fine for years on Debian 11 or 12 inherit this failure mode on upgrade without touching a single Plex setting.
The failure mode
Plex handles most audio transcoding with its bundled ffmpeg fork. But Dolby Digital Plus (EAC3) is licensed differently, so Plex ships a separate binary called EasyAudioEncoder, usually abbreviated EAE. It doesn't work like a normal encoder that reads stdin and writes stdout. It's a watch-folder daemon: Plex drops audio into a directory, EAE picks it up, converts it, and writes the result back. That watch folder lives under a per-instance temp directory that looks like this:
/tmp/pms-4f3a2b1c-9d8e-7f6a-5b4c-3d2e1f0a9b8c/EasyAudioEncoder/
The important detail: Plex creates that directory tree exactly once, when the plexmediaserver service starts. There's no health check on it, no recreation logic, no periodic touch. As long as the service keeps running, Plex assumes the directory it made on day one is still there.
Meanwhile, systemd-tmpfiles has its own opinion about /tmp. On most modern distros, /usr/lib/tmpfiles.d/tmp.conf contains a rule like this:
# Clear /tmp entries older than 10 days, /var/tmp after 30
q /tmp 1777 root root 10d
q /var/tmp 1777 root root 30d
And systemd-tmpfiles-clean.timer fires 15 minutes after boot and then once a day, removing anything under /tmp whose access, modification, and change times are all older than the age threshold. If you're a heavy Plex user who transcodes EAC3 daily, the timestamps stay fresh and you never notice. If your household mostly direct-plays and only occasionally hits EAC3 content, the watch folder sits idle, crosses the 10-day line, and gets reaped.
From that point on, the server is a zombie in one specific dimension. Everything that doesn't need EAE works. Anything that does fails at session start.
What it looks like in the logs
The client-side error is useless: "Conversion failed. The transcoder failed to start up." The actual story is in Plex Media Server.log:
ERROR - [Req#a4f/Transcode] EAE watchfolder is not writable:
/tmp/pms-4f3a2b1c-.../EasyAudioEncoder/Convert to WAV (to 8ch or less) (~4f3a)/
ERROR - [Req#a4f/Transcode] Transcode runner appears to have died
DEBUG - Job exit code 187
Exit code 187 from the transcoder job plus "EAE watchfolder is not writable" is the signature. If you go look, the path either doesn't exist at all or the pms-* parent is gone entirely. You can confirm the cleanup timer is the culprit by checking when it last ran:
systemctl list-timers systemd-tmpfiles-clean.timer
ls -ld /tmp/pms-* 2>/dev/null || echo "gone"
The immediate fix is boring:
systemctl restart plexmediaserver
Restarting recreates the whole /tmp/pms-* tree and EAC3 transcodes work again, instantly. Which is exactly why this problem generates so many confused forum threads that end with "restarted it and it works now, no idea why." The restart fixes the symptom and destroys the evidence, and ten days of idle EAE later it's back.
The permanent fix: a tmpfiles.d exclusion
You don't need to disable /tmp cleaning, and you shouldn't. The tmpfiles.d format has an exclusion type built for exactly this. Drop one file on the host running Plex:
# /etc/tmpfiles.d/plex-eae.conf
# Exempt Plex's per-instance temp tree from age-based cleanup.
# Lowercase 'x' ignores the path AND everything below it.
x /tmp/pms-*
Then verify systemd actually picked it up:
systemd-tmpfiles --cat-config | grep -A1 plex-eae
The character matters here, and it's an easy place to get burned. tmpfiles.d defines two exclusion types that look almost identical:
-
x /tmp/pms-*excludes the matching paths and their entire contents from cleaning. This is what you want. -
X /tmp/pms-*excludes only the directory itself. Its contents still age out, which puts you right back in the same failure with a slightly different shape: thepms-*directory survives but theEasyAudioEncodersubtree inside it gets reaped.
Globs are legal in exclusion rules and evaluated at cleaning time, so the rule keeps working even though the UUID in the directory name changes on every service restart.
To prove the fix without waiting ten days, force a cleanup pass with an aggressive age and watch the directory survive:
# Dry-run style check: run the cleaner with a 1-second age threshold
touch -d "30 days ago" /tmp/pms-*/EasyAudioEncoder 2>/dev/null
systemd-tmpfiles --clean
ls -ld /tmp/pms-*/EasyAudioEncoder && echo "exclusion works"
If the directory is still there after --clean runs against a backdated mtime, the rule is live. This kind of "verify the fix actually engages" step is the same discipline I argued for in the Longhorn read-only mounts post: a service that reports healthy while an underlying filesystem assumption has silently broken is the worst class of failure, because nothing pages you until a user complains.
The alternative fix: move EAE out of /tmp entirely
If you'd rather not maintain an exclusion rule, you can relocate Plex's temp tree to a path systemd-tmpfiles doesn't manage. EAE derives its working directory from the process environment, not from the "Transcoder temporary directory" setting in the Plex UI. That UI setting moves the video transcode segments, but the EAE watch folders follow TMPDIR. So changing the setting in the web UI does not fix this problem, which is a trap plenty of people fall into before finding the real mechanism.
A systemd drop-in handles it cleanly:
systemctl edit plexmediaserver
[Service]
Environment=TMPDIR=/var/lib/plexmediaserver/tmp
ExecStartPre=/usr/bin/mkdir -p /var/lib/plexmediaserver/tmp
After a daemon-reload and restart, the pms-* tree lands under a path with no age rule attached. The tradeoff is that nothing cleans it up anymore, so orphaned trees from unclean shutdowns accumulate until you notice. The x exclusion in /tmp doesn't have that problem, because the directory still gets wiped on reboot like everything else in /tmp. That's the main reason I'd pick the exclusion rule over the relocation: it changes the minimum necessary behavior and leaves the rest of the /tmp lifecycle intact.
There's a third option worth knowing about even if you don't use it: PrivateTmp=true in the unit. Systemd's private tmp directories get mounted under /tmp/systemd-private-*, and stock tmp.conf ships exclusion rules for those paths, so they're immune to aging by design. Plex's packaged unit doesn't enable it, and flipping it on changes how the service sees paths shared with other processes, so I'd treat it as trivia rather than the recommended fix here.
Gotchas and adjacent traps
Debian 13 flipped the default. Debian historically did not age out /tmp contents on a running system, which is why this bite pattern was mostly a Fedora/Arch/RHEL story for years. Trixie moved /tmp to tmpfs and enabled the 10-day /tmp and 30-day /var/tmp cleanup rules by default. If your Plex LXC or VM got upgraded to Debian 13, you inherited this behavior with zero warning. The exact same Plex install that ran for two years without an EAE incident now has a ten-day fuse that resets only on service restart.
LXC makes the uptime trap worse. Containers restart less often than you think. A Proxmox host reboot cycles every VM, but LXCs with long-running services rack up months of uptime effortlessly, and every one of those days is a day the tmpfiles timer inside the container keeps ticking. Long uptime feels like a stability trophy. For any service that stages state in /tmp at startup and never checks on it again, uptime is actually the risk factor. If you're running Plex inside an unprivileged LXC (a reasonable choice, and the general pattern is covered in Building a Production Homelab), put the tmpfiles.d exclusion inside the container, since that's where the timer that does the reaping lives.
Docker installs behave differently. A Plex container image doesn't run systemd inside it, so there's no tmpfiles timer to reap anything, and /tmp lives and dies with the container. This failure mode is specific to package installs on systemd hosts and systemd-based LXCs. If you migrated from Docker to a native package and suddenly hit this after a couple of weeks, that's why.
Don't fix it by disabling the timer. Masking systemd-tmpfiles-clean.timer works, but now nothing ages out /var/tmp either, and every other well-behaved consumer of the aging policy loses it too. Scoped exclusions exist precisely so you don't have to make that trade.
Plex isn't the only service with this shape. Anything that creates sockets, PID files, or working directories under /tmp at startup and holds a path reference for the life of the process is exposed. PostgreSQL's Unix socket default, some JVM apps with java.io.tmpdir scratch state, and various daemons with startup-created lock directories all have variants of this. Distros ship tmpfiles exclusions for the common ones (X11 sockets, systemd's own private dirs). Third-party packages are on their own, and Plex's package doesn't ship one. Auditing long-running services for this dependency class is the kind of infrastructure-drift review I end up doing in consulting engagements more often than any glamorous architecture work, because drift between OS policy and application assumptions is invisible until it isn't.
Takeaway
The application didn't break. The OS didn't malfunction. Two correct behaviors, Plex creating its EAE workspace once at startup and systemd-tmpfiles aging out idle /tmp entries, combined into a failure with a built-in delay timer. That's what makes it nasty: the cause and the symptom are separated by ten days and belong to two different layers of the stack.
The fix is a one-line file, x /tmp/pms-* in /etc/tmpfiles.d/plex-eae.conf, verified with systemd-tmpfiles --cat-config and a forced --clean pass. Reach for this pattern any time a long-running service treats /tmp as if it were persistent, and be suspicious of any "it works after a restart" fix where nobody can explain what the restart actually repaired. On a systemd host, a startup-created /tmp directory plus long uptime is a scheduled outage; the only question is the date.
Top comments (0)