Skip to content

search_missing re-searches the same N items forever: wanted list is sorted DESCENDING by lastSearchTime (missing sortDirection) #376

Description

@BlueWizarding

Summary

search_missing can permanently re-search the same MAX_CONCURRENT_SEARCHES items while items that have never been searched are never reached. It logs a normal success line every cycle, so it looks healthy the whole time.

In my case it re-searched the same 2 episodes 18 times in a row while 261 missing episodes had never been searched once.

Version: decluttarr v2.1.0 (commit dd474de), Sonarr 4.0.19.2979.

Cause

src/utils/wanted_manager.py::_get_arr_records sends sortKey but no sortDirection:

sort_key = f"{self.arr.detail_item_key}s.lastSearchTime"
params = {"page": "1", "pageSize": total_records_count, "sortKey": sort_key}

For this key the *arr API defaults to descending, so the list comes back most-recently-searched first, and items with lastSearchTime: null (never searched) sort last.

src/jobs/search_handler.py::_filter_wanted_items then takes from the top:

return items[: self.job.max_concurrent_searches]

So it selects the items it most recently searched, searches them again, and they stay at the head. The never-searched tail is unreachable.

Verified against a live Sonarr

Same endpoint, same sortKey, only sortDirection varies. First three lastSearchTime values:

DEFAULT (what decluttarr sends):  ['2026-07-27T21:27:42Z', '2026-07-27T21:27:37Z', '2026-07-27T21:25:04Z']
&sortDirection=ascending:         ['NEVER', 'NEVER', 'NEVER']
&sortDirection=descending:        ['2026-07-27T21:27:42Z', '2026-07-27T21:27:37Z', '2026-07-27T21:25:04Z']

The default is descending, and ascending produces the order the code clearly intends.

Why MIN_DAYS_BETWEEN_SEARCHES=0 turns this into total starvation

_filter_recent_searches is the only thing that can evict the recently-searched head:

if last_time + timedelta(days=self.job.min_days_between_searches) < now:

With min_days_between_searches = 0 this is last_time < now, always true, so nothing is ever filtered. Combined with the descending order, the same top N are selected every single cycle, forever.

This makes 0 a genuine footgun. It reads like "no throttling, search freely", but its actual effect is "the backlog is permanently unreachable". Any non-zero value masks the sort bug, which is likely why this has gone unnoticed: the documented examples use 7.

Suggested fix

Request the direction explicitly:

params = {
    "page": "1",
    "pageSize": total_records_count,
    "sortKey": sort_key,
    "sortDirection": "ascending",
}

Least-recently-searched first, with never-searched items leading, which is what the job intends and makes it correct at any min_days_between_searches including 0.

Optionally also warn at startup when MIN_DAYS_BETWEEN_SEARCHES=0, since that currently disables the only protection against this.

Workaround for anyone hitting it

Set MIN_DAYS_BETWEEN_SEARCHES to any non-zero value. After changing 0 to 7, my next cycle immediately searched two episodes that had never been searched, and the never-searched count began falling for the first time.

Symptom to look for: the same titles in Job 'search_missing' triggered a search for N items cycle after cycle, while your *arr still reports a large missing count.

Thanks for decluttarr, it does a lot of quiet work here.

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