qBittorrent's auto-remove racing arr imports
Symptoms looked like the same old "files imported but not really" pattern I'd dealt with before, but the root cause this time was subtler — and lived on the qBittorrent side instead of the arr side.
What was happening
The arr apps would mark queue items as "downloaded" but the import would silently fail. Files weren't where the arr expected them. The torrents themselves were gone from qBittorrent entirely. The arr would then re-grab the same release on the next pass, and the whole thing would loop.
This had been gradually getting worse over a couple of weeks. Some imports worked fine, others didn't. Couldn't find a pattern at first.
What I found
qBittorrent's Tools > Options > BitTorrent > Seeding Limits has an "auto-remove-on-ratio" option. When a torrent hits its share ratio (or its seed time limit), qBittorrent removes the torrent entry from its list. Depending on the MaxRatioAction setting, it can also delete the underlying files.
In this case MaxRatioAction was set to "remove only" — not "remove + delete." So the files stayed on disk. But the arr's bookkeeping is "torrent hash X is in the queue, watch for its completion event." When qBittorrent removes the entry, the arr never sees a completion event because the entry is gone before completion fires. The arr's queue item sits indefinitely waiting for an event that will never come, then eventually times out and re-grabs.
The race was: small torrents finishing and hitting their seed ratio inside the arr's polling window. The arr would scan, not see the torrent yet (just grabbed), come back five minutes later, and the torrent had already finished, seeded enough to ratio out, and been removed. Net effect from the arr's perspective: torrent vanished mid-flight.
The fix
Pick one of two coordinated configurations. Either:
A. qBittorrent owns removal. Set MaxRatioAction=3 (remove + delete files) and tell the arr to leave completed downloads alone (removeCompletedDownloads=false). qBittorrent does the import-recognition window first, then qBittorrent cleans up.
B. The arr owns removal. Set MaxRatioAction=2 (pause torrent on ratio — keep entry, don't delete) and let the arr be responsible for removing the torrent after import. removeCompletedDownloads=true on the arr side.
I went with B because the arr already has the import-success signal and is the better source of truth for "yes this file made it into the library and we can clean up the torrent." qBittorrent's pause-on-ratio means the entry stays around indefinitely, which I prefer to a race.
The change on the qBittorrent side:
# qBittorrent.conf
[BitTorrent]
Session\MaxRatioAction=2 # pause, don't remove
On each arr's download client config:
{
"removeCompletedDownloads": true,
"removeFailedDownloads": true
}
What I'd do differently
Same lesson as the other torrent cleanup post: two cleanup processes is one too many. The pattern generalizes — any time two systems share responsibility for the lifecycle of an artifact, write down which one is the owner and configure the other one to keep its hands off. I now keep a one-pager in my homelab docs that lists "owner of cleanup" for every category of artifact: torrents, completed downloads, log files, MariaDB dumps, container snapshots, etc. Boring, but it makes "wait, did I configure that to delete here or there?" questions answerable in seconds.