Quick answer

What this guide helps you do

Fix an empty Jellyfin library when scans find no media. Check storage mounts, paths, Linux permissions, Docker mappings, new-file access, scans, and logs in the correct order.

Jellyfin beginner path

New to Jellyfin? Follow this order.

These guides form the SmallGrid Jellyfin path: install it, fix folder access, solve empty libraries, reduce unnecessary transcoding, then choose the right mini PC.

  1. Jellyfin on Ubuntu: Low-Power Setup, Media Folders and Reboot Checks
  2. Give Jellyfin Access to Media Folders on Ubuntu
  3. Jellyfin Direct Play vs Transcoding: Differences, CPU Use and How to Check
  4. Best Mini PC Specs for Jellyfin: What Actually Matters

Difficulty

Beginner-friendly

Focus

Jellyfin setup and troubleshooting

Best used for

Practical setup, fixes, and checks

Printable helper

Prefer to work through this step by step?

Download the matching checklist and tick off the common causes while you work through the guide.

Quick answer

If Jellyfin is not showing files, do not reinstall it first.

Check the path from the storage layer upwards:

  1. confirm the media exists on the host
  2. confirm the disk, pool, USB drive, or network share is mounted
  3. confirm the Jellyfin service or Docker container can list the files
  4. confirm Jellyfin uses the exact path visible inside its own environment
  5. run a scan and inspect the logs

For a native Ubuntu installation:

sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

For Docker:

docker exec jellyfin find /media -maxdepth 3 -type f | head -20

Interpret the result:

ResultMeaning
Files are listedFilesystem access works; check the Jellyfin library path, scan, naming, library type, and logs
Permission deniedThe service account or container identity cannot traverse or read the path
Path does not existThe configured path or Docker destination is wrong
Folder is emptyThe storage may not be mounted, the host source may be wrong, or the bind mount points at an empty directory

The important test is not whether your own SSH user can see the files. It is whether Jellyfin can see them from the environment in which Jellyfin actually runs.


What this guide covers

This is the broad diagnostic guide for a Jellyfin library that is empty, incomplete, or unable to find files.

It helps you locate the failing layer:

  • host storage
  • persistent mount
  • Linux path traversal and read access
  • Docker bind mount
  • Jellyfin library path
  • inherited permissions on newly created files
  • library scan
  • naming, extensions, and library type
  • Jellyfin logs

Once the failing layer is known, use the narrower guide linked in that section.

This page intentionally does not repeat every detailed repair procedure:


SmallGrid verification environment

This workflow is based on the SmallGrid home media server:

Host:             Ubuntu Server
Storage pool:     MergerFS
Host TV path:     /srv/media_pool/TV
Jellyfin runtime: Docker
Container TV path:/tv
Jellyfin path:    /tv

The server also uses Sonarr and qBittorrent, so the diagnostic order has to distinguish between:

  • storage not being mounted
  • a Docker source/destination mismatch
  • Jellyfin being unable to read the mounted files
  • newly imported files receiving different access
  • a scan or identification problem

Example paths such as /mnt/media and /media are used elsewhere in this guide because they are easier to adapt. Use the real paths from your own host and Compose configuration.


Diagnostic decision table

What the check showsMost likely causeNext action
Host path does not existWrong path or missing mount pointConfirm the real storage path with findmnt, lsblk -f, and the Compose file
Host path exists but is emptyDisk, pool, USB drive, or network share is not mountedRepair the mount before changing Jellyfin
Your user sees files but native jellyfin does notLinux permissions or parent-folder traversalCheck namei -l, ownership, groups, and ACLs
Host sees files but Docker container does notWrong bind mount, wrong destination, or old container configurationInspect active mounts and recreate the service from the correct Compose project
Container sees files but Jellyfin does notWrong library folder, wrong library type, or scan problemUse the exact container path and rescan
Old media appears but new imports do notOwnership, group, umask, or default ACL differsCompare one working file with one missing file
Media disappears after rebootStorage was not mounted when Jellyfin startedValidate persistent mounts and service ordering
Files are readable but unidentifiedNaming, extension, folder structure, or library typeCheck layout and logs

Step 1: Confirm the media exists on the host

Inspect the exact host path:

ls -ld /mnt/media
find /mnt/media -maxdepth 3 -type f | head -20

For the SmallGrid TV path, the equivalent check is:

ls -ld /srv/media_pool/TV
find /srv/media_pool/TV -maxdepth 3 -type f | head -20

A useful result contains real media files:

/mnt/media/tv/Show Name/Season 01/Show Name - S01E01.mkv

If find returns nothing, stop here. Jellyfin cannot index files that are absent from the host path.

Check for case-sensitive path mistakes:

/mnt/media/tv
/mnt/Media/TV

These are different paths on Linux.

Count files for later comparison

A count is useful when comparing the host with the container:

find /mnt/media -type f | wc -l

Record the result. The container-side count should be broadly consistent for the same mounted tree.


Step 2: Confirm the storage is mounted

A mount-point directory can exist even when the actual storage is absent. Jellyfin may then scan an empty directory underneath the intended mount.

Check the target:

findmnt /mnt/media
findmnt -no SOURCE,TARGET,FSTYPE,OPTIONS /mnt/media
lsblk -f

For a MergerFS pool:

findmnt -T /srv/media_pool
findmnt -no SOURCE,TARGET,FSTYPE,OPTIONS -T /srv/media_pool

Expected evidence includes:

  • the intended source
  • the intended target
  • the expected filesystem type
  • mount options that permit the required access

If findmnt returns nothing, fix the storage layer before changing permissions or Jellyfin settings.

Validate persistent mounts

Inspect /etc/fstab:

grep -vE '^\s*(#|$)' /etc/fstab

After making a change:

sudo mount -a
findmnt /mnt/media

A silent mount -a followed by the expected findmnt result is a useful pre-reboot validation.


Step 3: Check the path configured in Jellyfin

Open:

Dashboard → Libraries → select the library → Manage folders

The path must match what Jellyfin can see.

Native installation example:

/mnt/media/movies

Docker example:

/media/movies

SmallGrid Docker example:

/tv

Do not put a host-only path into Jellyfin unless the same path is mounted at the same destination inside the container.

For this mapping:

volumes:
  - /srv/media/movies:/media/movies:ro

Jellyfin must use:

/media/movies

not:

/srv/media/movies

Step 4: Test access as Jellyfin

Native Ubuntu installation

Run the checks as the service account:

sudo -u jellyfin ls -la /mnt/media
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

Possible outcomes:

Files are listed

The native Jellyfin service can read the path. Continue to library settings, scans, naming, and logs.

Permission denied

Check every parent directory:

namei -l /mnt/media/movies

Jellyfin needs directory traversal permission on every directory in the path, not only read permission on the final folder.

Inspect ACLs:

getfacl -p /mnt/media
getfacl -p /mnt/media/movies

Follow the dedicated Ubuntu permissions guide for the full repair workflow.

Folder is empty

Compare the result with your normal user:

find /mnt/media -maxdepth 3 -type f | head -20
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20

If both are empty, return to the mount and source path. If only Jellyfin is empty or denied, investigate access.

Docker installation

Test the destination inside the running container:

docker exec jellyfin ls -la /media
docker exec jellyfin find /media -maxdepth 3 -type f | head -20

For the SmallGrid TV mapping:

docker exec jellyfin find /tv -maxdepth 3 -type f | head -20

This is stronger evidence than reading the Compose file alone because it tests the running container.


Step 5: Verify the active Docker bind mount

Inspect the active mounts:

docker inspect jellyfin \
  --format '{{range .Mounts}}{{println .Type "|" .Source "|" .Destination "|" .Mode}}{{end}}'

Expected shape:

bind | /srv/media/movies | /media/movies | ro

SmallGrid path relationship:

bind | /srv/media_pool/TV | /tv | ro

Check all three values:

  1. Source exists and contains files on the host.
  2. Destination is the path used inside Jellyfin.
  3. Mode is appropriate; read-only is normally enough for media.

If the expected mapping is absent, check which Compose project created the container:

docker inspect jellyfin \
  --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}'

docker inspect jellyfin \
  --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}'

Then apply the correct configuration:

docker compose config
docker compose up -d

Re-check docker inspect after recreation.


Step 6: Separate mapping problems from permission problems

Use this sequence:

find /srv/media/movies -maxdepth 2 -type f | head
docker inspect jellyfin \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'
docker exec jellyfin find /media/movies -maxdepth 2 -type f | head

Interpretation:

HostActive mappingContainerDiagnosis
Files visibleCorrectFiles visibleMapping and basic access work
Files visibleMissing or wrongEmpty/missingBind-mount problem
Files visibleCorrectPermission deniedContainer identity or host permissions
EmptyCorrect or wrongEmptyHost storage or source path problem

Do not apply chmod -R 777. It hides the diagnostic signal and grants more access than Jellyfin normally needs.


Step 7: Check parent traversal and permissions safely

For a native service:

namei -l /mnt/media/movies
id jellyfin

For a container, first identify the runtime user:

docker exec jellyfin id

Then inspect the host path:

namei -l /srv/media/movies
getfacl -p /srv/media/movies

The required fix depends on the container image and user model. LinuxServer images commonly use PUID and PGID; other images may use different configuration.

Keep this broad guide diagnostic. Apply the detailed repair from Jellyfin Docker Permissions once the failure is confirmed as access rather than mapping.


Step 8: Check whether only new files are missing

A different problem exists when:

  • old files remain visible
  • files imported recently by Sonarr, Radarr, qBittorrent, or another service do not appear

Compare one working item and one missing item:

stat -c '%A %U:%G %n' \
  "/mnt/media/tv/Working Show" \
  "/mnt/media/tv/New Show"

getfacl -p "/mnt/media/tv/Working Show"
getfacl -p "/mnt/media/tv/New Show"

Compare:

  • owner
  • group
  • directory execute permission
  • file read permission
  • ACL entries
  • default ACL inheritance
  • downloader or importer umask

Do not recursively rewrite the whole library before identifying the difference.

Use Jellyfin Not Scanning New Files for the dedicated workflow.


Step 9: Check removable and network storage

NTFS and exFAT

On NTFS and exFAT, mount options often control effective ownership and permissions.

Inspect them:

findmnt -no TARGET,SOURCE,FSTYPE,OPTIONS /mnt/media

Relevant options may include:

uid=
gid=
umask=
fmask=
dmask=

Repeated chmod commands may not survive a remount. Fix the mount configuration instead.

SMB or CIFS

Check that the share is mounted:

findmnt -t cifs

Then test access:

sudo -u jellyfin find /mnt/media -maxdepth 2 -type f | head

CIFS access may depend on:

uid=
gid=
file_mode=
dir_mode=

NFS

Check the client mount and server-side export permissions. UID/GID mapping may matter.

If the network storage is unavailable when Jellyfin starts, fix the mount dependency and then rescan.


Step 10: Check naming, extensions, and library type

Poor naming usually causes identification or metadata problems rather than a completely empty library. Still, inspect the structure once path access is proven.

Recommended movie layout:

/mnt/media/movies/Film Name (2024)/Film Name (2024).mkv

Recommended television layout:

/mnt/media/tv/Show Name/Season 01/Show Name - S01E01.mkv

Inspect extensions:

find /mnt/media -maxdepth 4 -type f \
  -printf '%f\n' | sed -n '1,30p'

Check for:

  • incomplete downloads
  • temporary files
  • files without media extensions
  • television content added to a movie library
  • movie content added to a television library
  • unexpected nested folders

Step 11: Rescan and inspect logs

Run a manual scan:

Dashboard → Libraries → Scan All Libraries

Restart after correcting mounts or access:

Native:

sudo systemctl restart jellyfin

Docker:

docker restart jellyfin

Read recent logs.

Native:

sudo journalctl -u jellyfin --since "10 minutes ago" --no-pager

Docker:

docker logs --since 10m jellyfin

Filter likely access and path failures:

docker logs jellyfin 2>&1 |
  grep -Ei 'permission|denied|not found|inaccessible|scan|mount'

Look for:

  • Permission denied
  • path not found
  • inaccessible directories
  • unavailable mounts
  • scan failures
  • unsupported or skipped files
  • database errors

A scan that finishes almost immediately can indicate that Jellyfin found no accessible files.


Verified SmallGrid case: host, pool, container, and library agreed

The following verification uses the real SmallGrid path relationship, with private filenames omitted.

1. Confirm the MergerFS pool

findmnt -T /srv/media_pool

The active target was /srv/media_pool, exposed as a MergerFS filesystem.

2. Confirm the host library

find /srv/media_pool/TV -type f | wc -l

The active storage branches contained 1,539 media files in total at the time of verification.

3. Confirm the active Docker mapping

docker inspect jellyfin \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

The television library used this path relationship:

/srv/media_pool/TV -> /tv

4. Confirm visibility inside the container

docker exec jellyfin find /tv -type f | wc -l

The host and Jellyfin-visible media counts matched for the active pool.

5. Confirm the Jellyfin library path

The television library used:

/tv

6. Final result

Storage mounted:          yes
Host media visible:       yes
Docker mapping correct:   yes
Container media visible:  yes
Host/container counts:    matched
Jellyfin healthy:         yes
Library path:             /tv

This case demonstrates the correct evidence chain. A matching final state does not prove every future scan will succeed, but it proves that the storage, bind mount, and container visibility layers are aligned.


Exact troubleshooting sequence

Native installation

findmnt /mnt/media
find /mnt/media -maxdepth 3 -type f | head -20
namei -l /mnt/media
sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head -20
systemctl status jellyfin --no-pager
sudo journalctl -u jellyfin --since "10 minutes ago" --no-pager

Docker installation

findmnt /srv/media
find /srv/media -maxdepth 3 -type f | head -20
docker inspect jellyfin \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'
docker exec jellyfin find /media -maxdepth 3 -type f | head -20
docker logs --since 10m jellyfin

Stop at the first failed layer. Do not change later layers until the earlier one is confirmed.


Final verification

Confirm all of these:

  1. The intended storage is mounted.
  2. The host path contains real media files.
  3. The native Jellyfin user or Docker container can list those files.
  4. The active Docker source and destination are correct, where applicable.
  5. Jellyfin uses the exact path visible inside its runtime environment.
  6. A manual scan completes without path or permission errors.
  7. At least one previously missing item appears.
  8. Newly imported media also appears.
  9. The storage and library remain available after a controlled restart or reboot.

Useful count comparison for Docker:

find /srv/media -type f | wc -l
docker exec jellyfin find /media -type f | wc -l

Counts can differ when the host path contains files outside the mounted subtree, but unexpected differences should be investigated.



Recap

When a Jellyfin library is not showing files, test the complete evidence chain:

storage → host path → service/container visibility → Jellyfin library path → scan → logs

For native Jellyfin:

sudo -u jellyfin find /mnt/media -maxdepth 3 -type f | head

For Docker:

docker exec jellyfin find /media -maxdepth 3 -type f | head

If Jellyfin cannot list the files, fix the mount, mapping, or permissions first.

If Jellyfin can list the files, focus on the exact library folder, scan behaviour, naming, library type, and log messages.

Downloadable checklist

Save the matching PDF checklist

Use these while working through the guide, or keep a copy for the next time the same problem appears.

More downloads are available in the SmallGrid checklists section.

Next guide

What to read next

Continue the setup path with these closely related guides.

Jellyfin guide cluster

More Jellyfin fixes and setup guides

These guides link the main Jellyfin setup, permissions, remote access, direct play, and hardware topics together.