{"record":{"id":"4ddf7ca4be9abb2a","repo":"infiniflow/ragflow","slug":"invalid-results-format-from-searxng","errorCode":null,"errorMessage":"Invalid results format from SearXNG","messagePattern":"Invalid results format from SearXNG","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/tools/searxng.py","lineNumber":116,"sourceCode":"\n            try:\n                search_params = {\"q\": query, \"format\": \"json\", \"categories\": \"general\", \"language\": \"auto\", \"safesearch\": 1, \"pageno\": 1}\n\n                with pin_dns(_ssrf_hostname, _ssrf_ip):\n                    response = requests.get(f\"{searxng_url}/search\", params=search_params, timeout=10)\n                response.raise_for_status()\n\n                if self.check_if_canceled(\"SearXNG processing\"):\n                    return\n\n                data = response.json()\n\n                if not data or not isinstance(data, dict):\n                    raise ValueError(\"Invalid response from SearXNG\")\n\n                results = data.get(\"results\", [])\n                if not isinstance(results, list):\n                    raise ValueError(\"Invalid results format from SearXNG\")\n\n                results = results[: self._param.top_n]\n\n                if self.check_if_canceled(\"SearXNG processing\"):\n                    return\n\n                self._retrieve_chunks(results, get_title=lambda r: r.get(\"title\", \"\"), get_url=lambda r: r.get(\"url\", \"\"), get_content=lambda r: r.get(\"content\", \"\"))\n\n                self.set_output(\"json\", results)\n                return self.output(\"formalized_content\")\n\n            except requests.RequestException as e:\n                if self.check_if_canceled(\"SearXNG processing\"):\n                    return\n\n                last_e = f\"Network error: {e}\"\n                logging.exception(f\"SearXNG network error: {e}\")\n                time.sleep(self._param.delay_after_error)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/tools/searxng.py#L98-L134","documentation":"After the SearXNG response body passes the dict check, the component reads data.get('results', []) and requires it to be a list (agent/tools/searxng.py:116). A 'results' key holding an object, string, number, or null raises ValueError('Invalid results format from SearXNG'). The body was JSON but does not follow the SearXNG search-response shape.","triggerScenarios":"The endpoint returns a JSON error object like {\"error\": ...} or {\"results\": {\"error\": ...}}; a proxy returns a JSON API error envelope; a non-SearXNG JSON service is configured at searxng_url; a SearXNG plugin mutates the response shape.","commonSituations":"SearXNG behind an API gateway that wraps responses; wrong base URL pointing at a JSON admin/route instead of the search route; version differences or plugins altering the payload.","solutions":["curl the exact URL the component uses ('{searxng_url}/search?q=test&format=json') and confirm the top-level 'results' key is a JSON array.","Point searxng_url at the SearXNG base URL (e.g. http://searxng:8080), not at a proxy or admin endpoint that reshapes bodies.","Disable/adjust SearXNG plugins or proxy transforms that alter the response structure.","If the body is an error envelope, fix the underlying error (bad format, limiter block) first - it is not a client-side parsing bug."],"exampleFix":"# verify expected shape\ncurl 'http://searxng:8080/search?q=test&format=json'\n# expected: {\"query\": \"test\", \"results\": [{\"title\": ..., \"url\": ..., \"content\": ...}, ...]}","handlingStrategy":"try-catch","validationCode":"data = response.json()\nresults = data.get(\"results\") if isinstance(data, dict) else None\nif not isinstance(results, list):\n    raise ValueError(f\"unexpected SearXNG shape: {type(results).__name__}\")","typeGuard":"def is_searxng_payload(data) -> bool:\n    return isinstance(data, dict) and isinstance(data.get(\"results\", []), list)","tryCatchPattern":"try:\n    ...\nexcept ValueError as e:\n    if \"results format\" in str(e):\n        log.raw_body(data)  # capture the malformed payload for diagnosis\n        return []          # degrade to no results rather than failing the canvas","preventionTips":["Pin the SearXNG version in deployments so response shape changes surface in testing.","Do not put transforming proxies between RAGFlow and SearXNG.","Smoke-test the exact /search?format=json call after every SearXNG config change."],"tags":["searxng","agent","search","http","schema"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}