Skip to content

DbContext concurrency exception in DownloadClientQueuePoller causes "Using cached queue data" and downstream "Import Blocked" failures #783

Description

@f1fson

Title

DbContext concurrency exception in DownloadClientQueuePoller causes "Using cached queue data" and downstream "Import Blocked" failures

Summary

On v1.2.2-canary (commit 4555ad2, the #599 queue-polling refactor), the queue poller for a download client (observed with both SABnzbd and qBittorrent configured simultaneously) repeatedly throws an EF Core concurrency exception:

System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext.
   at Listenarr.Application.Downloads.Queue.DownloadClientQueuePoller.FetchAsync(DownloadClientConfiguration client, TimeSpan clientQueueTimeout, TimeSpan staleSnapshotMaxAge) in /home/runner/work/Listenarr/Listenarr/listenarr.application/Downloads/Queue/DownloadClientQueuePoller.cs:line 90

This is immediately followed by a secondary cascade error on the same connection:

[ERR] [Microsoft.EntityFrameworkCore.Database.Command] Failed executing DbCommand (0ms) [Parameters=[@downloadClientId='?' (Size = 23)], CommandType='Text', CommandTimeout='30']
System.InvalidOperationException: ExecuteReader can only be called when the connection is open.

The UI surfaces this as:

Using cached queue data — SABnzbd using cached data 5s/10s old after a client error

This repeats on every poll cycle (every ~5s), so the client is treated as permanently degraded even though the actual SABnzbd/qBittorrent API calls succeed (visible a few lines earlier in the log: Retrieved 1 total items from SABnzbd (queue + history)).

Suspected root cause

DownloadClientQueuePoller.FetchAsync appears to reuse a single injected DbContext instance across concurrent polling tasks (one per configured download client, e.g. SABnzbd + qBittorrent polled in parallel). EF Core's DbContext is not thread-safe; concurrent use throws ConcurrentMethodInvocation. This looks like a regression from the v1.2.2-canary "split queue display and monitor polling contracts" refactor (PR #599), since it introduces separate/parallel polling paths per client.

Possible downstream impact

We suspect this concurrency failure is also a contributing cause of the still-recurring "Import Blocked" / Inconsistency: Download has no path set failures (#631), even after the #632 fix. If a poll cycle throws before it finishes writing Download.DownloadPath from the SABnzbd/qBittorrent history storage field, the import processor can still pick up the download in an inconsistent state on the next cycle. We observed this exact sequence twice after upgrading to v1.2.2-canary: SABnzbd/qBittorrent reports storage/completed correctly, but Download.finalPath stays empty and the item is stuck in ImportBlocked with importAttempts: 0 forever (no automatic retry).

Environment

  • Listenarr: v1.2.2-canary (ghcr.io/listenarrs/listenarr:canary, image built 2026-06-30T20:34:27Z, commit 4555ad2 / build 3b25386)
  • Download clients configured simultaneously: SABnzbd 5.x and qBittorrent (both enabled at the same time)
  • Docker Desktop on Windows, all services on a shared bridge network

Steps to reproduce

  1. Configure both a SABnzbd and a qBittorrent download client in Listenarr at the same time (both enabled).
  2. Let Listenarr poll both clients' queues concurrently for a few minutes.
  3. Observe the Activity page banner "Using cached queue data" appearing repeatedly, and the corresponding EF Core concurrency exception in the logs.
  4. Separately, a completed download's finalPath may remain empty and the item gets stuck in ImportBlocked despite the source download client reporting a valid, verified storage path (verified independently via each download client's own API).

Expected behavior

  • Each concurrent poll of a download client should use its own scoped DbContext instance (e.g. via IDbContextFactory<T> or a fresh scope per polling task), so parallel polling of multiple clients does not throw.
  • A failed poll cycle should not leave the Download record in a state where DownloadPath/finalPath never gets populated on a later, successful cycle (currently importAttempts stays at 0 forever and there is no way to manually retry an ImportBlocked download from the UI or API — only GET/DELETE are available on /api/v1/downloads/{id}).

Logs

2026-07-28 14:08:33.104 +02:00 [INF] [Listenarr.Infrastructure.DownloadClients.Sabnzbd.SabnzbdAdapter] Retrieved 1 total items from SABnzbd (queue + history)
2026-07-28 14:08:33.104 +02:00 [ERR] [Microsoft.EntityFrameworkCore.Query] An exception occurred while iterating over the results of a query for context type 'Listenarr.Infrastructure.Persistence.ListenArrDbContext'.
System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
2026-07-28 14:08:33.105 +02:00 [WRN] [Listenarr.Application.Downloads.Queue.DownloadClientQueuePoller] Error getting queue snapshot from download client SABnzbd
   at Listenarr.Application.Downloads.Queue.DownloadClientQueuePoller.FetchAsync(DownloadClientConfiguration client, TimeSpan clientQueueTimeout, TimeSpan staleSnapshotMaxAge) in /home/runner/work/Listenarr/Listenarr/listenarr.application/Downloads/Queue/DownloadClientQueuePoller.cs:line 90
2026-07-28 14:08:33.154 +02:00 [INF] [Listenarr.Application.Downloads.Queue.DownloadQueueService] Client SABnzbd has 1 queue items
2026-07-28 14:08:33.155 +02:00 [WRN] [Listenarr.Application.Downloads.Queue.DownloadQueueService] Using cached queue snapshot for client SABnzbd (age: 5.0s, reason: error)

Related: #631, #632

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions