BUG: Blocklist-search fails due to queue ID type mismatch (string vs number) #48

Closed
opened 2026-05-24 22:10:14 +01:00 by Gandalf · 3 comments
Owner

Summary

The "Blocklist and search" feature is broken for all users. Clicking the blocklist button on a download (e.g. the film "Project Hail Mary", arrQueueId: 905000340, arrType: radarr) consistently returns a 403 Download not found or permission denied error.

Root Cause

The server-side lookup in server/routes/dashboard.js uses strict equality (===) to find the matching download:

const download = allDownloads.find(d => d.arrQueueId === arrQueueId && d.arrType === arrType);
  • d.arrQueueId is populated from the Radarr/Sonarr queue API response as a number (e.g. 905000340).
  • arrQueueId from req.body originates from the client SPA via a DOM dataset attribute, which is always a string (e.g. "905000340").
  • Due to the type mismatch, 905000340 === "905000340" evaluates to false, so the lookup always fails and returns 403.

Evidence

Server log (live environment, 2026-05-24):

[Blocklist] Download not found: { arrQueueId: 905000340, arrType: 'radarr' }

Client log confirms user clicked blocklist at 21:01:19, 21:01:32, and 21:02:35.

Steps to Reproduce

  1. Open the dashboard on a Radarr or Sonarr download with a pending queue entry.
  2. Click the "Blocklist and search" button.
  3. The action silently fails; the download is not removed and no re-search is triggered.
  4. Server logs show [Blocklist] Download not found.

Proposed Fix

Cast both sides of the comparison to String before comparing:

const download = allDownloads.find(d => d.arrQueueId != null && String(d.arrQueueId) === String(arrQueueId) && d.arrType === arrType);

This fix will be released in version 1.7.16.

Severity

High — The blocklist-and-search feature is completely non-functional for all users. There is no workaround within the UI.

## Summary The "Blocklist and search" feature is broken for all users. Clicking the blocklist button on a download (e.g. the film "Project Hail Mary", `arrQueueId: 905000340`, `arrType: radarr`) consistently returns a `403 Download not found or permission denied` error. ## Root Cause The server-side lookup in `server/routes/dashboard.js` uses strict equality (`===`) to find the matching download: ```js const download = allDownloads.find(d => d.arrQueueId === arrQueueId && d.arrType === arrType); ``` - `d.arrQueueId` is populated from the Radarr/Sonarr queue API response as a **number** (e.g. `905000340`). - `arrQueueId` from `req.body` originates from the client SPA via a DOM `dataset` attribute, which is always a **string** (e.g. `"905000340"`). - Due to the type mismatch, `905000340 === "905000340"` evaluates to `false`, so the lookup always fails and returns `403`. ## Evidence Server log (live environment, `2026-05-24`): ``` [Blocklist] Download not found: { arrQueueId: 905000340, arrType: 'radarr' } ``` Client log confirms user clicked blocklist at `21:01:19`, `21:01:32`, and `21:02:35`. ## Steps to Reproduce 1. Open the dashboard on a Radarr or Sonarr download with a pending queue entry. 2. Click the "Blocklist and search" button. 3. The action silently fails; the download is not removed and no re-search is triggered. 4. Server logs show `[Blocklist] Download not found`. ## Proposed Fix Cast both sides of the comparison to `String` before comparing: ```js const download = allDownloads.find(d => d.arrQueueId != null && String(d.arrQueueId) === String(arrQueueId) && d.arrType === arrType); ``` This fix will be released in version `1.7.16`. ## Severity **High** — The blocklist-and-search feature is completely non-functional for all users. There is no workaround within the UI.
Gandalf added the Kind/Bug
Reviewed
Confirmed
1
Priority
High
2
labels 2026-05-24 22:10:14 +01:00
Author
Owner

Resolved in commit 83c9d4d164.

Resolved in commit 83c9d4d1646356d56eeb614004f455314115b663.
Gandalf reopened this issue 2026-05-24 22:27:08 +01:00
Author
Owner

Regression: Fix in v1.7.16 was insufficient — issue persists in production

Updated Root Cause Analysis

Post-release investigation of live server debug logs on sofarr.i3omb.com confirms the blocklist feature is still failing after v1.7.16. The server logs still show:

[Blocklist] Download not found: { arrQueueId: 439913856, arrType: 'radarr' }

The v1.7.16 fix cast both sides of the comparison to String, which was the correct approach — but it was applied to the wrong data source.

The permission check at line 693 of dashboard.js calls:

const allDownloads = await downloadClientRegistry.getAllDownloads();
const download = allDownloads.find(d => d.arrQueueId != null && String(d.arrQueueId) === String(arrQueueId) && d.arrType === arrType);

downloadClientRegistry.getAllDownloads() fetches raw download client data directly from qBittorrent, SABnzbd, etc. — these are unmatched objects with no Sonarr/Radarr queue metadata. The arrQueueId field is only populated during DownloadMatcher.js processing (which runs during the SSE/dashboard build from the *arr cache). Because qBittorrent's normalizeDownload() never sets arrQueueId, the lookup always returns undefined for any qBittorrent torrent, regardless of type casting.

Correct Fix

The permission check should validate against the Sonarr/Radarr queue cache records directly (where id is the queue record ID), rather than against raw download client data. The fix will replace the downloadClientRegistry.getAllDownloads() lookup with a direct cache lookup of poll:sonarr-queue / poll:radarr-queue records, matching by String(record.id) === String(arrQueueId).

This will be released in v1.7.17.

## Regression: Fix in v1.7.16 was insufficient — issue persists in production ### Updated Root Cause Analysis Post-release investigation of live server debug logs on `sofarr.i3omb.com` confirms the blocklist feature is **still failing** after v1.7.16. The server logs still show: ``` [Blocklist] Download not found: { arrQueueId: 439913856, arrType: 'radarr' } ``` The v1.7.16 fix cast both sides of the comparison to `String`, which was the correct approach — but it was applied to the **wrong data source**. The permission check at line 693 of `dashboard.js` calls: ```js const allDownloads = await downloadClientRegistry.getAllDownloads(); const download = allDownloads.find(d => d.arrQueueId != null && String(d.arrQueueId) === String(arrQueueId) && d.arrType === arrType); ``` `downloadClientRegistry.getAllDownloads()` fetches **raw download client data** directly from qBittorrent, SABnzbd, etc. — these are unmatched objects with no Sonarr/Radarr queue metadata. The `arrQueueId` field is only populated during `DownloadMatcher.js` processing (which runs during the SSE/dashboard build from the *arr cache). Because qBittorrent's `normalizeDownload()` never sets `arrQueueId`, the lookup **always returns `undefined`** for any qBittorrent torrent, regardless of type casting. ### Correct Fix The permission check should validate against the **Sonarr/Radarr queue cache records** directly (where `id` is the queue record ID), rather than against raw download client data. The fix will replace the `downloadClientRegistry.getAllDownloads()` lookup with a direct cache lookup of `poll:sonarr-queue` / `poll:radarr-queue` records, matching by `String(record.id) === String(arrQueueId)`. This will be released in v1.7.17.
Author
Owner

Resolved in v1.7.17

This issue has been resolved. The commit 7690d95 correctly addresses the root cause of the blocklist-and-search feature failure.

Root Cause

The v1.7.16 fix correctly cast both sides of the queue ID comparison to String, but the lookup was performed against downloadClientRegistry.getAllDownloads(), which returns raw download-client data (qBittorrent, SABnzbd, etc.) that never has arrQueueId populated.

For qBittorrent torrents specifically, QBittorrentClient.normalizeDownload() does not set arrQueueId at all, so the lookup always returned undefined and the request was rejected with 403.

Fix Applied

The permission check in POST /api/dashboard/blocklist-search now looks up the queue record directly from the Sonarr/Radarr queue cache (poll:sonarr-queue / poll:radarr-queue) where record.id is the numeric queue ID, using String() casting on both sides to handle the DOM-dataset (string) vs API response (number) type difference.

Files Changed

  • server/routes/dashboard.js - Fixed lookup to use queue cache
  • tests/integration/dashboard.test.js - Updated tests to use cache-based lookup
  • CHANGELOG.md - Added v1.7.17 entry documenting the regression fix

Version

  • Resolved in: v1.7.17
  • Commit: 7690d95

All 883 tests pass. The release will be tagged v1.7.17.


Commit: 7690d95
Release: v1.7.17

## Resolved in v1.7.17 This issue has been resolved. The commit `7690d95` correctly addresses the root cause of the blocklist-and-search feature failure. ### Root Cause The v1.7.16 fix correctly cast both sides of the queue ID comparison to `String`, but the lookup was performed against `downloadClientRegistry.getAllDownloads()`, which returns **raw download-client data** (qBittorrent, SABnzbd, etc.) that never has `arrQueueId` populated. For qBittorrent torrents specifically, `QBittorrentClient.normalizeDownload()` does not set `arrQueueId` at all, so the lookup always returned `undefined` and the request was rejected with `403`. ### Fix Applied The permission check in `POST /api/dashboard/blocklist-search` now looks up the queue record directly from the Sonarr/Radarr queue cache (`poll:sonarr-queue` / `poll:radarr-queue`) where `record.id` is the numeric queue ID, using `String()` casting on both sides to handle the DOM-dataset (string) vs API response (number) type difference. ### Files Changed - `server/routes/dashboard.js` - Fixed lookup to use queue cache - `tests/integration/dashboard.test.js` - Updated tests to use cache-based lookup - `CHANGELOG.md` - Added v1.7.17 entry documenting the regression fix ### Version - **Resolved in**: v1.7.17 - **Commit**: `7690d95` All 883 tests pass. The release will be tagged v1.7.17. --- **Commit**: 7690d95 **Release**: v1.7.17
Gandalf added the Area/Matching label 2026-05-28 11:58:41 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Gandalf/sofarr#48