{"record":{"id":"a84b141daac1c8b4","repo":"infiniflow/ragflow","slug":"invalid-response-from-searxng","errorCode":null,"errorMessage":"Invalid response from SearXNG","messagePattern":"Invalid response from SearXNG","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/tools/searxng.py","lineNumber":112,"sourceCode":"        last_e = \"\"\n        for _ in range(self._param.max_retries + 1):\n            if self.check_if_canceled(\"SearXNG processing\"):\n                return\n\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","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/tools/searxng.py#L94-L130","documentation":"The SearXNG agent component GETs {searxng_url}/search with format=json and requires the parsed body to be a non-empty dict (agent/tools/searxng.py:112). A JSON body that is empty, a list, a string, or null raises ValueError('Invalid response from SearXNG'). This usually means the endpoint did not return a SearXNG JSON search payload at all.","triggerScenarios":"searxng_url points at a SearXNG instance where the 'json' output format is disabled (default in modern SearXNG), so /search returns an HTML page or 403-related body; the URL points at a non-SearXNG service; a proxy returns a JSON array or error object; response.json() parses something that is not an object.","commonSituations":"Self-hosted SearXNG without enabling json in settings.yml search.formats; trailing-path mistakes in searxng_url; reverse proxy rewriting responses; SearXNG limiter returning a non-JSON block page.","solutions":["In SearXNG settings.yml enable the JSON format: search: formats: [html, json], then restart SearXNG.","Verify manually: curl 'http://<host>/search?q=test&format=json' must return a JSON object with a results array.","Check searxng_url has no trailing /search or wrong port - the code appends /search itself.","If a proxy or bot-limiter intercepts the request, whitelist the RAGFlow server IP or adjust limiter settings."],"exampleFix":"# before (searxng settings.yml)\nsearch:\n  formats:\n    - html\n\n# after\nsearch:\n  formats:\n    - html\n    - json","handlingStrategy":"try-catch","validationCode":"import requests\n\ndef searxng_ready(base_url):\n    try:\n        r = requests.get(f\"{base_url}/search\", params={\"q\": \"test\", \"format\": \"json\"}, timeout=5)\n        return r.ok and isinstance(r.json(), dict)\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    output = searxng_component.run(query)\nexcept ValueError as e:\n    if \"Invalid response\" in str(e):\n        # endpoint healthy check failed: fall back to another search tool or surface config error\n        raise ConfigError(\"SearXNG JSON format disabled or URL wrong - check settings.yml\") from e\n    raise","preventionTips":["Enable json in SearXNG search.formats at setup time and verify with curl.","Monitor /search responses in staging after SearXNG upgrades - formats reset to defaults on some upgrades.","Keep searxng_url as the bare base URL; the component appends /search."],"tags":["searxng","agent","search","configuration","http"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}