← Back to Wiki
Media / Storage

New Media Never Shows Up in Jellyfin: inotify Can't See Another NFS Client's Writes

A film imported by Radarr at 17:08 was still missing from Jellyfin hours later. It was readable, in the right folder, in a format Jellyfin already handled elsewhere in the same library — it simply had zero rows in Jellyfin's database. Real-time monitoring was enabled the whole time, and could never have worked. This is structural, not a misconfiguration, and the same trap catches Plex and Emby on any network share written by a different machine.

Share on X

First, rule out the things it usually is

Before blaming the watcher, confirm the file is genuinely fine — this takes a minute and saves you chasing permissions:

# readable by the user the media server runs as?
sudo -u jellyfin ls -l "/mnt/movies/Young Guns (1988)/"

# does the library path match what the server has configured?
# and is the format one it already handles?

In this case all three checked out. The library already indexed twelve other .iso files, so full-disc images clearly weren't the issue. The item was simply never scanned: the last library scan ran at 14:05, the import happened at 17:08, and the next scheduled scan wasn't until roughly 02:03. It was going to appear eventually — up to twelve hours later.

Why real-time monitoring can't help

Jellyfin's EnableRealtimeMonitor — "Enable real time monitoring" in Library settings — uses inotify, the Linux kernel's filesystem notification interface. inotify reports changes the local kernel observes on a filesystem.

An NFS client's kernel does not observe writes made by a different NFS client. When another machine writes a file to the share, your kernel isn't told; nothing happened locally. There is no event to deliver, so the watcher never fires. It isn't slow or unreliable — there is genuinely nothing there to see.

The setting still shows as enabled, which is the worst part: it looks like a working mechanism and provides nothing.

Downloader host Radarr / Sonarr writes the file NAS / NFS export file now exists Media server host Jellyfin, same share kernel saw nothing inotify only reports what the LOCAL kernel does. The write happened on another machine, so there is no event to deliver — the watcher is enabled and idle forever.
The structural gap. Same file, same share, two machines. Only the writer's kernel generates events, and the media server isn't the writer.

This applies to SMB/CIFS too, and to any setup where the *arr stack runs on a different host, in a different VM or container, or on a different VLAN from the media server. If the media server is the machine doing the writing, real-time monitoring works fine — that's why plenty of people never see this.

The usual fix, and when you can't have it

The normal answer is to have the downloader tell the media server: in Radarr or Sonarr, add a Connect notification (Settings → Connect → Emby/Jellyfin) that fires on import and triggers a library scan. If you can do that, do that — it's event-driven and immediate.

It assumes the downloader can reach the media server's API, which isn't always true. If your *arr stack lives on an isolated VLAN — a common and sensible arrangement for torrent traffic — then the connection you'd need runs from the isolated network into your LAN, which is exactly the direction that isolation exists to prevent. Punching a hole through it so a library can refresh is a poor trade.

Poll from the media server side instead

Invert it. Rather than the writer notifying the reader, have the reader — which is already allowed to talk to itself — watch the mount and trigger its own scan. A systemd timer on the media server host, every few minutes:

#!/usr/bin/env bash
# /usr/local/bin/jellyfin-autoscan.sh
set -euo pipefail
STATE=/var/lib/jellyfin-autoscan/state
mkdir -p "$(dirname "$STATE")"

# Cheap fingerprint of the libraries: newest mtime + entry count.
now=$(find /mnt/movies /mnt/tv -maxdepth 2 -printf '%T@ %p\n' 2>/dev/null \
      | sort -rn | head -20 | md5sum | cut -d' ' -f1)
prev=$(cat "$STATE" 2>/dev/null || true)

if [ "$now" != "$prev" ]; then
  echo "$now" > "$STATE"
  # Debounce: only scan once things have stopped changing.
  exit 0
fi

# Unchanged since last run — the copy has finished. Scan if we haven't already.
if [ ! -f "$STATE.scanned" ] || [ "$STATE" -nt "$STATE.scanned" ]; then
  curl -fsS -X POST "http://127.0.0.1:8096/Library/Refresh" \
       -H "X-Emby-Token: $JELLYFIN_API_KEY"
  touch "$STATE.scanned"
fi

Two details that matter more than the script:

# /etc/systemd/system/jellyfin-autoscan.timer
[Unit]
Description=Poll media mounts and trigger a Jellyfin library scan

[Timer]
OnBootSec=5min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target
systemctl enable --now jellyfin-autoscan.timer
systemctl list-timers jellyfin-autoscan.timer

Prevention

The one-line version: inotify only reports what the local kernel does, so a media server watching an NFS share written by another machine will never be told anything — enable a push notification from the downloader if your network permits it, otherwise poll the mount from the media server and debounce before scanning.