Skip to content

Premiumize: sync-found entries are listed but serve no files over WebDAV (follow-up to #373) #423

Description

@IIxauII

Follow-up to #373.

Summary

On beta, a Premiumize entry that was found by sync is listed as a folder over WebDAV but serves none of its files. The entry record itself still holds the full file list, so /api/torrents looks healthy. PROPFIND with Depth: 1 on that folder returns no children, and every GET of a file it lists returns 404.

The literal complaint in #373 is fixed: all transfers show up now. But some of the folders that show up are empty, so the content is still not reachable. On my box this left 94 library symlinks dead, and the built-in repair reported the entries as healthy.

What actually breaks

The problem is the name index (items.db), not the provider and not the mount.

Two entries can render the same folder name:

  1. An arr grabs a release. The entry is stored under the magnet infohash H1. The name index gets one record per file in folder F, each tagged with H1.
  2. Premiumize sync later sees the same cloud transfer. transfer/list carries no infohash, so beta derives a synthetic key H2 (6639571, the Premiumize: sync mounts 1 of N torrents and /torrents/add rejects uncached, while direct API calls work #373 fix). That is a second entry, with the same name, so the same folder F.
  3. On a later sync, H1 is no longer on the remote. detectTorrentChanges removes the premiumize placement, the entry has no placements left, and it is deleted.
  4. Storage.Delete calls removeFromEntryItem, which deletes every file record in F tagged H1. That empties the item, so the whole folder is deleted from the name index — even though entry H2 still renders F.

After that the two sides disagree:

  • Folder listings are built from entry metadata (ForEachMeta), so F is still listed in __all__.
  • Folder children come from GetEntryItem(F) in getTorrentChildren, which now returns "key not found", so the folder has zero children and every file 404s.

Nothing rebuilds the index on its own, because it is only written when an entry is written. So the folder stays empty until that entry happens to be written again.

Repair does not catch it either: repair asks the provider whether the files exist, and they do. It never compares the provider against what the WebDAV tree actually serves.

In code this is provider-independent, but in practice only Premiumize hits it, because it is the only provider that re-keys the same release. Every other provider reports a real infohash (realdebrid.go t.Hash, debrid_link.go t.HashString, alldebrid.go magnet.Hash, torbox.go data.Hash).

Evidence

Same entry, two views:

Probe (curl straight at :8282, no rclone or FUSE in the path) Sync-found PM entry Grab-made PM entry Any RD entry
Listed in PROPFIND /webdav/__all__/ Depth 1 yes yes yes
PROPFIND <entry>/ Depth 0 207, 84 bytes 207 207
PROPFIND <entry>/ Depth 1 0 children 24 hrefs files listed
GET <entry>/<file it lists in /api/torrents> 404 200 / 206 200 / 206
Files in the entry record 24 23 fine

Repair on the same box, with every broken entry in the candidate set:

repair: { enabled: true, source: "arr", strategy: "per_file", auto_repair: false }
POST /api/repair/run  ->  candidates=131 probed=131 healthy=130 broken=1 unknown=0

130 of 131 healthy while 94 symlinks were dead.

Provider side was fine throughout: transfer/list returned all 9 transfers as finished, and nothing was deleted.

How to check a database for this

Compare the folder names in the entries store metadata with the keys in the items store. Any folder name that has a live entry but no item record is in this state. On my box that was exactly 7 folders, all Premiumize, and it matched the broken folders one for one.

Repro

  1. Run Decypharr with a Premiumize provider.
  2. Grab a release through an arr so the entry is created from the magnet.
  3. Let a later sync pick the same transfer up under its synthetic key, and let the sync after that drop the grab-made entry.
  4. PROPFIND the folder: it is listed, and it has no children.

Fix

PR: #424

Two parts:

  • Deleting an entry rebuilds the name index from the entries that are still live, and only removes the folder when no entry maps to it any more.
  • Startup runs the same rebuild once over the database, so installs that are already in this state recover without waiting for a write.

Both scans read entry metadata only, so a healthy database costs no extra disk reads.

I have been running this on my own box since today: startup logged Rebuilt folders missing from the name index count=7, the folder that returned 84 bytes now returns 24 files, a ranged GET returns 206 with data, and the dead symlink count went from 94 to 0. It also survived a full sync afterwards.

Environment

  • ghcr.io/sirrobot01/decypharr@sha256:84d31557fddbe8200ba9bf433210f929b4777cf2c23a947922715fa2442a7402, reports v2.5.1-beta
  • Providers: realdebrid + premiumize, no selected_debrid
  • mount.type: "none", external rclone against http://127.0.0.1:8282/webdav
  • rootless podman 3.4.4, Ubuntu 22.04

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions