fix(search): tell a failed search apart from one with no results - #2377
Merged
Conversation
SearXNG being down and a query with no results used to reach the client as the same empty response, so both showed the red failure alert. fetchSearXNG and the client search service now propagate upstream failures instead of collapsing them into an empty array: /search/text and /search/images answer HTTP 502 on an outage, while a genuine zero-result search stays HTTP 200 with an empty array. The client maps that back to the states it already renders - failed shows the retry alert, completed with zero results shows the no-results alert - and the keyword fallback only fires on genuinely empty results.
A failed search no longer cleared the LLM grounding channel: updateLlmTextSearchResults was only called on the success path, and the reset block in searchAndRespond cleared text/image results, chat, and page contents but not llmTextSearchResults. So after a healthy search, a subsequent search that failed on an outage left the previous query's snippets/URLs in the channel, and the AI grounded its answer for the failed query on stale results. Clear the channel in the reset block (which runs at the start of every search, before startTextSearch), so a failed search, an enableTextSearch:false search, and a getKeywords throw before the try all leave the channel empty. Add a regression test that pre-populates the channel and asserts a failed search clears it, and update the failure-injection matrix and the stale configuration.md line that still described the pre-fix 'generic failure'.
felladrin
approved these changes
Aug 15, 2026
felladrin
left a comment
Owner
There was a problem hiding this comment.
@uuzzrm Pushed a fix to the branch for the stale-grounding issue. A failed search now clears the LLM channel in the reset block (updateLlmTextSearchResults([])), and I added a regression test that pre-populates the channel and asserts a failed search clears it (it goes red if the fix line is removed).
Two other things I spotted are pre-existing and not from this PR: a superseded search can still write its results into a newer run's channel and history (the results publish has no run-id guard, unlike readPageContents), and a getKeywords throw leaves textSearchState idle instead of failed. I'll track those separately so they don't block this.
Approving.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2336.
A SearXNG outage and a query with genuinely zero results used to reach the client as the exact same response, so both ended up with the red "Search failed" alert and its Retry button. Someone searching for something obscure got told the search failed, and a real outage looked like an ordinary empty result.
Server
fetchSearXNGno longer swallows upstream failures into an empty array - it logs the failure and rethrows, so an empty array now means exactly one thing: zero results./search/textand/search/imagesanswer HTTP 502 with a JSON error when SearXNG is unreachable; a zero-result search stays HTTP 200 with[].Client
searchText/searchImageslog and rethrow instead of returning[]on error.startTextSearchandstartImageSearchmark the statefailedonly when the request itself errors; a successful empty response leaves the statecompletedso the existing no-results alert actually renders.Docs & tests
docs/failure-injection.md: dropped the Known Limitations entry, updated the matrix rows for the two cases.Validation:
npx vitest runon the four affected files (90 passed),npx biome checkclean on all changed files,npx tsc --noEmitclean. (The repo's two doc-script tests fail on Windows for path-separator reasons unrelated to this change - they fail onmaintoo.)