Document data-loss incident, pause qbt-relink.sh
Babylon 5 S03/S04 (44 episodes) were destroyed during a relink attempt despite every safety check the script performs (HTTP status, save_path, content_path) passing. qBittorrent's own automatic incomplete-file management took further unrequested action after the script's calls succeeded - moving/truncating files at a location it still considered incomplete - which none of the script's checks could see coming since they only verify immediately after its own calls. No backup existed. Files could not be found anywhere on /data after a full search. Marking qbt-relink.sh unsafe until the interaction with qBittorrent's temp_path_enabled behavior is understood well enough to prevent this. Claude-Session: https://claude.ai/code/session_01HZQK6jHmdTpFjFZM8FUnqA
This commit is contained in:
@@ -5,6 +5,20 @@ description: Use Sonarr to add TV shows and manually import existing raw-named f
|
||||
|
||||
# Sonarr library migration/import
|
||||
|
||||
**⚠️ `qbt-relink.sh` is currently UNSAFE — do not use it until this warning is
|
||||
removed.** It caused real, apparently unrecoverable data loss (Babylon 5
|
||||
seasons 3 and 4, 44 episodes) on 2026-09-08: qBittorrent's own automatic
|
||||
incomplete-file management fought the script's manual `setLocation` calls
|
||||
across repeated resume/stop cycles and physically moved/destroyed the real
|
||||
files, even after every safety check the script performs (stopped state,
|
||||
confirmed `save_path`, confirmed `content_path`) reported success. See
|
||||
"Incident 3" below for the full detail. **The Sonarr import workflow itself
|
||||
(`sonarr.sh scan`/`import`) is unaffected and still safe** — it's specifically
|
||||
the qBittorrent-side relink step that's paused. Until this is fixed, leave
|
||||
qBittorrent's stale torrent entries alone after a Sonarr import rather than
|
||||
touching them — a `missingFiles` error in the qBittorrent UI is a much
|
||||
smaller problem than what happened here.
|
||||
|
||||
This repo's Sonarr manages TV show organization for both Jellyfin and Plex
|
||||
(they share the same `nas_media` library at `/data/video/tv`). The
|
||||
`claude-homelab` plugin's Sonarr skill (if installed) only covers
|
||||
@@ -130,7 +144,52 @@ or its `state` is `checkingDL` instead of `checkingUP`**, check
|
||||
`content_path` vs `save_path` directly — a mismatch means the recheck is
|
||||
running against the wrong location and will "succeed" at finding nothing.
|
||||
|
||||
### Incident: an unchecked `setLocation` call let a torrent start re-downloading
|
||||
### Incident 3: qBittorrent's own automatic file management destroyed real data despite every check passing — data loss, `qbt-relink.sh` is now paused
|
||||
|
||||
2026-09-08, same overall session, later batch. Even with incidents 1 and 2's
|
||||
fixes in place (`api_call` status checking, torrent stopped first,
|
||||
`save_path` *and* `content_path` both confirmed correct before proceeding),
|
||||
Babylon 5 S03 and S04 lost their actual files. The qBittorrent log
|
||||
(`/api/v2/log/main`) tells the story: after `setLocation` moved them to
|
||||
`Season 03`/`Season 04` (logged success), qBittorrent's *own* internal logic
|
||||
immediately enqueued and executed a further move of those same files **back**
|
||||
to `/data/torrents/incomplete/video/tv` on its own — nothing in the script
|
||||
requested this. A later resume cycle moved them back to `Season 03`/`04`
|
||||
again, but then repeated automatic resume/stop cycles followed (visible as
|
||||
alternating `"Torrent resumed"`/`"Torrent stopped"` log lines with no
|
||||
corresponding script action), and after those, both `Season 03` and
|
||||
`Season 04` folders were **completely empty** — confirmed via `ls`/`stat`
|
||||
from two separate containers, and a full search of `/data` found the files
|
||||
nowhere. 44 episodes, gone. No backup existed (the user had explicitly
|
||||
decided to proceed without one earlier in this project).
|
||||
|
||||
Best-guess mechanism: qBittorrent's `temp_path_enabled` incomplete-file
|
||||
management re-evaluates on every resume, independent of manual
|
||||
`setLocation`/`setDownloadPath` calls, and can decide to relocate — or,
|
||||
worse, truncate/overwrite in place expecting fresh downloaded data — files
|
||||
at a location it still considers "incomplete" (i.e. never successfully
|
||||
verified as 100% via a *clean* recheck). Since these torrents' recheck kept
|
||||
getting interrupted/retriggered across multiple attempts (network/NFS
|
||||
slowness caused several manual re-triggers in this session), the torrent
|
||||
seems to have never reached a stable "verified complete" state internally,
|
||||
leaving it perpetually eligible for this automatic (and here, destructive)
|
||||
relocation — regardless of what the script's own state checks reported.
|
||||
|
||||
**This means the safety checks this script relies on (`save_path`,
|
||||
`content_path`, HTTP status) are necessary but not sufficient** — they
|
||||
confirm the *script's* requests succeeded, but qBittorrent can still take
|
||||
further unrequested action afterward that undoes or destroys the result,
|
||||
and none of that is visible to a script that only checks immediately after
|
||||
its own calls. `qbt-relink.sh` is paused (see the warning at the top of this
|
||||
file) until this is understood well enough to prevent it — likely candidates
|
||||
for a real fix: disabling `temp_path_enabled` globally before relinking
|
||||
(and confirming no other torrent depends on it) as a global preference, an
|
||||
approach that fully separates the qBittorrent-tracked download from the
|
||||
Sonarr-organized library so they never share a path, or verifying via a
|
||||
polling loop that a recheck reaches a genuinely stable end state (not just
|
||||
"currently reports 100% right now") before considering a torrent safe.
|
||||
|
||||
### Incident 1: an unchecked `setLocation` call let a torrent start re-downloading
|
||||
|
||||
The first version of `qbt-relink.sh` fired `setLocation`/`renameFile`/
|
||||
`recheck` with `curl -s ... > /dev/null`, discarding the HTTP status. Running
|
||||
|
||||
Reference in New Issue
Block a user