Skip to main content

Jellyfin: Deleting Phantom Library Entries

·3 mins· loading · loading
Jellyfin Sql
Table of Contents
Quick fix for Jellyfin phantom library entries

Intro
#

I’m using Jellyfin version 10.11.4 and recently reorganized some media only to find that one of my libraries kept the old filepaths in the database as phantom entries. This meant these old entries were still visible even though they were now in a different library (which correctly picked them up).

Investigating
#

These were things I tried that didn’t work:

  • Individual Library Scan on ‘bad’ library
  • Full Library Scan
  • Individual Library Scan on ‘bad’ library and replace all metadata
  • Remove ‘bad’ library, ran full library scan, and then re-added the library
  • Ran multiple cleanup/etc jobs in the jellyfin admin panel

I then tried searching the internet and found a few github issues from 2024 or earlier, and also found this forum post from 2024 where theguymadmax mentions opening the TypedBaseItems table in the library.db. But I found that Jellyfin has since updated their database schema so the referenced table doesn’t exist. Before exploring the database further, I looked at the logs for clues and found this:

[INF] [41] Emby.Server.Implementations.Library.LibraryManager: Removing item, Type: "Series", Name: "mediaName", Path: "/libraryPath/mediaPath", Id: fce0bde8-b5d8-1d70-ce80-7ade30e313c7
[ERR] [41] Microsoft.EntityFrameworkCore.Database.Command: Failed executing DbCommand ("4"ms) [Parameters=["@__date_1='?' (DbType = DateTime), @__p_0='?' (Size = 1600)"], CommandType='Text', CommandTimeout='30']"
""UPDATE \"UserData\" AS \"u\"
SET \"ItemId\" = '00000000-0000-0000-0000-000000000001',
    \"RetentionDate\" = @__date_1
WHERE \"u\".\"ItemId\" IN (
    SELECT \"p\".\"value\"
    FROM json_each(@__p_0) AS \"p\"
)"
[ERR] [41] Microsoft.EntityFrameworkCore.Query: An exception occurred while executing an 'ExecuteUpdate' operation for context type '"Jellyfin.Database.Implementations.JellyfinDbContext"'."
""Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: UserData.ItemId, UserData.UserId, UserData.CustomDataKey'.

From this error I found there was a constraint violation in the UserData table when the phantom Path was queried. Following the error entry I found the following:

   at Jellyfin.Server.Implementations.Item.BaseItemRepository.DeleteItem(IReadOnlyList`1 ids)
   at Emby.Server.Implementations.Library.LibraryManager.DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, Boolean notifyParentItem)

The prior database schema utilized a TypedBaseItems table but from the logs I knew I was looking for the BaseItem table and that the database was searching the Path. This gave what I needed to write a simple SQL script to remove these entries.

The Fix: Sqlite database update
#

  1. Install sqlite or an SQL client (I like DBeaver Community)

  2. Turn off Jellyfin service/container

  3. Navigate to Jellyfin’s config/data folder. For me that was in my docker mount jellyfin/config/data/

  4. Create a backup of jellyfin.db

  5. Open the database

    • sqlite:

      sqlite3 jellyfin.db
      
      SQLite version 3.51.1 2025-11-28 17:28:25
      Enter ".help" for usage hints.
      sqlite> 
      
    • DBeaver: Create Connection -> Sqlite -> Select database and connect -> Once connected, right click database -> SQL Editor -> New SQL Script

  6. Run a basic query for the faulty BaseItem.Path.

    • Can add an OR statement if multiple paths were broken.
    • Keep the % as a wildcard.
    • (Dbeaver: Ctrl+Enter to execute)
    SELECT Path
    FROM BaseItems 
    WHERE Path LIKE '/libraryPath/mediaPath%'
        OR Path LIKE '/libraryPath/mediaPath2%'
        OR Path LIKE '/libraryPath/mediaPath3%'
        OR Path LIKE '/libraryPath/mediaPath4%'
        OR Path LIKE '/libraryPath/mediaPath5%';
    
  7. Review the output. This is a list of everything you’re about to delete from the database with the next command. If you need to adjust the library path(s) then repeat step 6 with another SELECT Path query.

  8. Delete jellyfin phantom/ghost entries:

    DELETE FROM BaseItems 
    WHERE Path LIKE '/libraryPath/mediaPath%'
        OR Path LIKE '/libraryPath/mediaPath2%'
        OR Path LIKE '/libraryPath/mediaPath3%'
        OR Path LIKE '/libraryPath/mediaPath4%'
        OR Path LIKE '/libraryPath/mediaPath5%';
    
  9. Save and Close Database

    • sqlite (saved automatically):
      .quit
      
    • Dbeaver: Ctrl+S to save, then close
  10. Turn on Jellyfin service/container

Conclusion
#

You should now be able to review your library and verify the old ‘phantom’ media entries have been removed.

Did you enjoy this post or find it helpful?

If so, please leave a like! It doesn't go into an algorithm—it just lets me know a human reader valued it in some way (you are human, right?)