Skip to content

Swapped Movie Doesn't Look in Comet, stops in AIOStreams #180

Description

@stevenmccord

Summary

Opening one specific movie in Jellyfin spins forever and never returns streams. The logs show InsertActionFilter.InsertMetaAsync retrying recursively, each attempt failing with:

SQLite Error 19: 'UNIQUE constraint failed: BaseItemProviders.ItemId, BaseItemProviders.ProviderId'

Because the insert never completes, execution never reaches the stream-resolution step (SyncStreams is never called for the item), so the client just buffers indefinitely.

The failure reproduces from a completely clean state — with the item's BaseItemProviders rows verified to be zero immediately before the insert — which means SaveItems is persisting a duplicate (ItemId, ProviderId) pair within a single insert batch, not colliding with pre-existing rows.

Environment

  • Jellyfin: 10.11.9
  • Gelato plugin: 0.26.15.1
  • DB: SQLite (EF Core schema)
  • Stream backend: AIOStreams → Comet (debrid). Backend confirmed healthy — see note below.

Affected item

  • Title: Swapped (2026)
  • IMDb: tt29552248
  • TMDB: 1007757
  • A same–clean-name sibling already exists in the library: episode "We Swapped Places" (tt21423786).
  • A library search for the title returns 9 results, and InsertActionFilter emits Media already exists; redirecting to canonical id <guid> before failing. The canonical id is deterministic — deleting the item and re-materializing regenerates the identical canonical GUID.

Steps to reproduce

  1. Library whose stream resolution is handled by Gelato (AIOStreams addon source).
  2. Use a title that (a) has a same–clean-name sibling already present in the library, and (b) triggers InsertActionFilter: Media already exists; redirecting to canonical id ... on insert.
  3. Open the item from search.

Expected: item materializes, SyncStreams runs, streams are returned.

Actual: insert throws the UNIQUE constraint error on BaseItemProviders.(ItemId, ProviderId); InsertActionFilter.InsertMetaAsync retries recursively; SyncStreams never fires; the client spins.

Evidence this is a single-batch self-collision, not stale state

The conflicting provider rows were deleted and the table verified empty for the canonical id, Jellyfin was restarted, and the item was opened fresh:

-- before opening the item, against the live DB (read-only):
SELECT hex(ItemId), ProviderId, ProviderValue
FROM BaseItemProviders
WHERE ProviderValue IN ('tt29552248','1007757');
-- returns: (no rows)

The very next insert still throws UNIQUE constraint failed: BaseItemProviders.ItemId, BaseItemProviders.ProviderId. With nothing pre-existing to collide with, the only way to violate that constraint is for the insert batch to contain the same (ItemId, ProviderId) twice.

The failing EF command parameters confirm which key is duplicated — ProviderId size 4 ("Imdb"), value size 10 ("tt29552248"):

Failed executing DbCommand [Parameters=[@p0=? (DbType=Guid), @p1=? (Size=4), @p2=? (Size=10)]]

The input meta is well-formed (single IMDb id)

The addon-supplied meta has exactly one IMDb reference and one TMDB reference — no duplicate id binding — so the duplicate is generated downstream of the meta, inside Gelato:

{
  "id": "tmdb:1007757",
  "imdb_id": "tt29552248",
  "name": "Swapped",
  "links": [
    { "name": "7.3", "category": "imdb", "url": "https://imdb.com/title/tt29552248" }
    // ...remaining links are share/genre/cast/director only; no second IMDb id binding
  ]
}

TMDB external_ids for 1007757 were also checked directly and contain a single, clean imdb_id: tt29552248.

Stack trace (trimmed)

Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
 ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: BaseItemProviders.ItemId, BaseItemProviders.ProviderId'.
   at Gelato.GelatoManager.SaveItems(IEnumerable`1 items, Folder parent)
   at Gelato.GelatoManager.SaveItem(BaseItem item, Folder parent)
   at Gelato.GelatoManager.InsertMeta(Folder parent, StremioMeta meta, User user, Boolean allowRemoteRefresh, Boolean refreshItem, Boolean queueRefreshItem, CancellationToken ct)
   at Gelato.Filters.InsertActionFilter.<>c__DisplayClass10_0.<<InsertMetaAsync>b__0>d.MoveNext()
   at Gelato.KeyLock.RunQueuedAsync(Guid key, Func`2 action, CancellationToken ct)
   at Gelato.Filters.InsertActionFilter.InsertMetaAsync(Guid guid, Folder root, StremioMeta meta, User user)
   at Gelato.Filters.InsertActionFilter.OnActionExecutionAsync(ActionExecutingContext ctx, ActionExecutionDelegate next)

The InsertMetaAsync → InsertMeta → SaveItems frames repeat on each retry (the loop).

Suspected cause

The failure is gated by the canonical-merge path: it only occurs on items that hit InsertActionFilter: Media already exists; redirecting to canonical id .... Ordinary titles (no redirect) insert and sync normally. This strongly suggests that when Gelato reconciles an incoming meta with an existing canonical item, it builds the provider-id collection by unioning/concatenating two provider sets without de-duplicating by ProviderId, then persists them in a single SaveItems batch — producing two (ItemId, "Imdb") rows and tripping the unique index.

The likely trigger for entering that merge path here is the same–clean-name sibling (tt21423786 "We Swapped Places") colliding with tt29552248 during dedup.

Notes

  • This never hits Comet, so I can't even get any versions of the stream
  • The backend is not implicated: the same IMDb id (tt29552248) resolves and returns streams normally through the identical AIOStreams → Comet path when requested via Stremio, so content availability and id resolution are fine.
  • DB-side cleanup (deleting the item row and orphaned provider rows) does not durably fix it, because re-materialization regenerates the same canonical id and re-triggers the duplicate insert.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions