Mopping the Floor With the Tap Running
Why: The new pipeline probe found Radarr items stuck since 2026-07-29, and Radarr — unlike Sonarr — has never had automatic queue cleanup. Building one exposed why the stalls never resolve, and it is a layer below where we were looking.
1. Two cleanup tools
~/bin/radarr-queue-cleanup.py — the Radarr counterpart to sonarr-queue-cleanup.sh (which has existed since 2026-05-29). Removes queue items that are errored, or completed-but-import-pending, and blocklists the dead ones so Radarr picks a different release. Dry-run by default.
~/bin/torbox-cleanup.py — retention for the TorBox account, which keeps every torrent forever. Deletes finished torrents older than 6 days. TorBox only: nothing on this server is touched, and already-imported media stays imported.
2. Safety design, since these are the only tools here that delete
Path gating (Radarr). Every item's outputPath is translated from the container path (/data/torbox_downloads) to its host path and checked against an allow-list of staging roots plus an explicit deny-list of Plex library roots. It fails closed — unmappable or unrecognised paths are refused. A refused item is still de-queued and blocklisted, which touches only Radarr's database and no files. 12 unit tests covering every Plex root, /media roots, $HOME, /, relative paths and ../ traversal were written and passed before the script ran once.
This mattered immediately: a queue item titled "Freeway (1996)" carried an outputPath belonging to "An Evening With Dua Lipa (2024)". The download client's path mapping cannot be assumed to match the title.
Fail-closed provenance (TorBox). Deletion requires proving a torrent is idle, which means reading every arr queue. If any arr is unreachable the script aborts rather than guessing. This fired for real on the first run: Lidarr returned 404 because it is still on API v1 while the others are on v3, and the script correctly refused to delete anything. Lidarr and Whisparr were only added to that check after the first dry run revealed Metric albums in TorBox — a Sonarr+Radarr-only check would have been blind to music grabs mid-import.
Verified no library impact. /media/plex1/Movies was snapshotted before and after every run: 1,599 directories, identical listing, 6.1 TB. TV and Music were never referenced.
3. The finding: we were cleaning the wrong layer
The first cleanup run removed 9 items and the queue dropped from 10 to 1. Six hours later the same item IDs were back. Not new grabs — the same records.
Inspecting rdt-client directly (its API needs a session login at POST /api/Authentication/Login) explains it:
rdt-client TV : 51 torrents — 38 with errors, 13 clean
rdt-client MOVIES : 44 torrents — 8 with errors, 36 clean
dominant error: "Could not add to provider: DIFF_ISSUE: Download already queued."
rdt-client attempts to add a release to TorBox, TorBox rejects it as a duplicate, and rdt-client keeps that failed record permanently. Sonarr and Radarr rebuild their queues from the download client, so every arr-level removal is undone on the next sync. This is the actual mechanism behind "I request media and it never arrives" — not a broken import, and not a dead release, but a permanent error record in the middle layer that the arrs faithfully keep re-displaying.
The general lesson: a cleanup at the wrong layer looks like it works. The queue really did drop from 10 to 1. Only checking again hours later revealed it had achieved nothing.
4. Status and what is deliberately not done
radarr-queue-cleanup.py— working, run manually. No cron yet: a tool that deletes should earn trust through manual runs first, and while rdt-client keeps re-serving dead records an automated run would just churn.torbox-cleanup.py— working, dry-run verified. Zero deletions eligible at 6 days: everything in TorBox is either newer than the threshold or still referenced by an arr. The gates are correct; there is simply nothing to clear yet. No cron yet.- rdt-client cleanup — NOT built. This is the layer that would actually fix the problem, and its delete endpoint is
POST /api/torrents/delete/{id}. It is left for a deliberate decision because, unlike the other two, it can remove local files, and that deserves its own scoping conversation rather than being tacked onto a cleanup session. - Orphaned staging directories under
/media/plex1/torbox_downloads/radarr/remain —removeFromClientcleared the client's records but not the files. Also left alone deliberately.
Two cleanup tools that are safe and correct, and a root cause that turns out to sit one layer below both of them.
← Back to Admin Hub