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.
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.
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.
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 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.
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