#6159·navidrome

[Bug]: Watcher selective scan leaves orphan folder rows when a new Artist/Album tree is created ("Parent folder not found for album cover art lookup")

Author: tay2501Created Sep 17, 2026Updated Sep 17, 2026

I confirm that:

  • I have searched the existing open AND closed issues to see if an issue already exists for the bug I've encountered
  • I'm using the latest version (running 0.63.2; I read the v0.64.0 scanner/ sources and could not find anything that would change this behavior, see below)

Version

0.63.2

Current Behavior

When a tool creates a new two-level directory (Artist/Album/track.mp3) inside a library while Navidrome is running, the folder watcher triggers a selective scan that inserts a folder row for Artist/Album, but no row for the newly created Artist folder. The Artist/Album row keeps a parent_id that points to a folder id that does not exist in the folder table.

These orphan rows are not repaired by the scheduled (non-full) scans. Every cover art request for such an album then logs:

level=warning msg="Artwork: Parent folder not found for album cover art lookup" parentID=4CuRL8UDm337MXN9PoCXsz

(albumRootParent() in core/artwork/folders_album.go gets ErrNotFound for the parent.)

In my case the tool is Explo, which downloads playlist tracks into a dedicated library as Artist/Album/Title.mp3. After one weekly run, 22 album folders (under 21 new artist folders) were orphaned. All 22 orphan rows have a created_at inside the window of the three watcher-triggered selective scans that ran during the download. Album folders created on earlier dates in the same library have no orphaned parents.

State of the DB after the run (library 3 is the Explo library):

sql
SELECT f.library_id, f.missing, count(*)
FROM folder f
WHERE f.parent_id <> ''
  AND NOT EXISTS (SELECT 1 FROM folder p WHERE p.id = f.parent_id)
GROUP BY 1, 2;
-- 3 | 0 | 22

Example: the folder Ado/残夢 exists with parent_id = 4CuRL8UDm337MXN9PoCXsz, the directory Ado/ exists on disk, but SELECT count(*) FROM folder WHERE id = '4CuRL8UDm337MXN9PoCXsz' returns 0.

Expected Behavior

A selective (watcher-triggered) scan should make sure that all ancestor folders of the scanned targets exist in the folder table (or should scan the nearest new ancestor instead), so that folder.parent_id always points to an existing row.

Steps To Reproduce

  1. Run Navidrome with the folder watcher enabled (default) and a library at /music/lib.
  2. While Navidrome is running, create a new artist and album in a single step, e.g. mkdir -p "/music/lib/NewArtist/NewAlbum" && cp track.mp3 "/music/lib/NewArtist/NewAlbum/".
  3. Wait for Watcher: Triggering scan for changed folders / Watcher: Scan completed.
  4. Query: SELECT id, parent_id FROM folder WHERE name = 'NewAlbum'; then check that parent_id exists in folder.
  5. Request the album cover art: the warning above is logged.

Workaround / confirmation: a full selective scan of the library root repairs it. navidrome scan --full -t 3:. created the 21 missing artist rows in 3.8s (library 3 folder count 439 -> 460, orphan count 22 -> 0, track count unchanged).

Environment

  • OS: Debian 13 (trixie), arm64 (Raspberry Pi 5)
  • Browser: n/a (clients: Web UI and a Subsonic iOS client)
  • Client: n/a

How Navidrome is installed?

Docker

Configuration

ND_SCANNER_SCHEDULE="0 5 * * *"
# Three libraries; the affected one is a local Docker volume (not a network/FUSE mount).
# Watcher settings are defaults.

Relevant log output

level=info msg="Watcher: Triggering scan for changed folders" numTargets=10
level=info msg="Scanner: Starting selective scan" fullScan=false numLibraries=1 numTargets=10
level=info msg="Scanner: Completed processing folder" audioCount=1 library=explo tracksImported=1 folder="Ado/桜日和とタイムマシン - 初夏"
...
level=info msg="Watcher: Scan completed"
...
level=warning msg="Artwork: Parent folder not found for album cover art lookup" parentID=4CuRL8UDm337MXN9PoCXsz

Anything else?

  • Possibly related: #5823 shows the same warning, although the cause described there is different.
  • My reading of v0.64.0 (unverified): resolveFolderPath() in scanner/watcher.go turns the file event into the Artist/Album directory. When the Artist directory is created, the change shows up on the library root (the log shows folder=. processed with its own audio count only). walkDirTree() in scanner/walk_dir_tree.go walks each target recursively, but I could not find any code that inserts missing ancestor folders of a target. So Artist/ never becomes a scanned folder.

Code of Conduct

  • I agree to follow Navidrome's Code of Conduct