Skip to content

ImportPending downloads whose client item vanished block re-grabs with 409 forever, and orphan cleanup can't reach them #758

Description

@t3chnaztea

Sibling of the case fixed in #755, filed separately because #640's design cares rule out the obvious fix.

The wedge

DownloadDuplicateGuard.HasActiveDownloadAsync treats ImportPending as active, so it blocks any re-grab of that audiobook (the API surfaces this as 409 "already active"). But DownloadOrphanCleanupService.GetCleanupReason only reconciles Queued/Downloading/Paused — deliberately, per #640: terminalizing ImportPending on a flaky snapshot would destroy pending imports.

The result: a download that completed in the client but whose files/queue item were removed before import (user deleted the finished torrent, seedbox cleanup, client history pruned) sits in ImportPending permanently. It blocks every future grab of that book and is invisible to the only mechanism that could clear it. Nothing self-heals; the user has to find the stale record in Activity and remove it by hand, with no hint from the 409 that this is the fix.

Possible directions (deliberately not a PR, since #640 constrains the design)

  1. Make the duplicate guard snapshot-aware instead of terminalizing: an ImportPending row whose external id is absent from a live snapshot (and has no active import job) stops counting as "active" for duplicate-guard purposes, without touching its state. No mass-terminalization risk; the record stays for manual review.
  2. On-demand reconcile before rejecting: when a grab is about to 409, run a scoped orphan check for that audiobook's client and only reject if the item is genuinely live in the client.
  3. Missing-since counter: extend cleanup to ImportPending only after continuous absence across N live snapshots plus a longer grace window (the Two cleanup paths never wired up: unbounded DownloadProcessingJobs; orphaned downloads never terminalized #640 "missing-since, not StartedAt" idea).
  4. At minimum, make the 409 actionable: include the stale download id and a hint ("remove it from Activity to re-grab") or offer a "remove stale and retry" affordance.

Happy to implement whichever direction maintainers prefer.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions