qBittorrent was deleting files before Sonarr could import them
Sonarr's queue kept stalling. Episodes would show up as grabbed, sit in the queue, and then quietly fail to import. Re-grabbing the same release didn't help — it would do the same thing.
What was happening
Queue full of "imported" items that never actually appeared on disk. Sonarr logs had a mix of "file not found" warnings and the dreaded "episode file already imported" message for files that had clearly never been imported anywhere.
What I found
qBittorrent has a setting called MaxRatioAction. It's an integer in qBittorrent.conf:
[BitTorrent]
Session\MaxRatioAction=3
The values: - 0 = pause torrent on ratio - 1 = remove torrent - 2 = enable super seeding - 3 = remove torrent AND delete files
Mine was at 3. qBittorrent was watching torrents hit their seed ratio, removing the entry, and deleting the files from the temp directory — all before Sonarr's import scan caught up. By the time Sonarr went looking, the source files were gone. Sonarr would mark the import as failed, the queue entry would stay, and on the next pass the same torrent would get re-grabbed.
The other half of the bug was that Sonarr had removeCompletedDownloads=true on the qBittorrent download client, which meant Sonarr was also racing to remove queue entries that qBittorrent had already nuked. The two cleanup paths were stepping on each other.
The fix
One config change in qBittorrent.conf:
Session\MaxRatioAction=0
Restart qbittorrent, then via the Sonarr API flip the download client to leave completed downloads alone:
curl -X PUT "$SONARR/api/v3/downloadclient/$ID" \
-H "X-Api-Key: $KEY" \
-d '{"removeCompletedDownloads": false, ...}'
Now qBittorrent pauses on ratio instead of deleting. Sonarr does the import, then I let qBittorrent handle its own cleanup on its own schedule.
What I'd do differently
Two cleanup processes is one cleanup process too many. Pick one tool to own the file lifecycle and tell the other one to keep its hands off. Same pattern applies in any pipeline where two services share a working directory — pick an owner, write it down, and configure the rest as read-mostly.