{"record":{"id":"05158ba1f525e4bf","repo":"infiniflow/ragflow","slug":"querit-api-response-must-be-a-json-object","errorCode":null,"errorMessage":"Querit API response must be a JSON object.","messagePattern":"Querit API response must be a JSON object\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"agent/tools/querit.py","lineNumber":170,"sourceCode":"        values = {\n            name: kwargs[name] if name in kwargs else getattr(self._param, name)\n            for name in (\n                \"count\",\n                \"chunks_per_doc\",\n                \"site_include\",\n                \"site_exclude\",\n                \"time_range\",\n                \"country_include\",\n                \"language_include\",\n            )\n        }\n\n        try:\n            _validate_search_inputs(**values)\n            payload = _build_payload(query, **values)\n            response_data = self._search(payload, api_key)\n            if not isinstance(response_data, dict):\n                raise TypeError(\"Querit API response must be a JSON object.\")\n\n            result_container = response_data.get(\"results\", {})\n            if not isinstance(result_container, dict):\n                raise TypeError(\"Querit API response field results must be an object.\")\n            results = result_container.get(\"result\", [])\n            if not isinstance(results, list):\n                raise TypeError(\"Querit API response field results.result must be an array.\")\n\n            reference_results = [item for item in results if isinstance(item, dict)]\n            if reference_results:\n                self._retrieve_chunks(\n                    reference_results,\n                    get_title=lambda item: _querit_text(item.get(\"title\")),\n                    get_url=lambda item: _querit_text(item.get(\"url\")),\n                    get_content=lambda item: _querit_text(item.get(\"snippet\")),\n                    get_score=lambda _item: 1,\n                )\n            else:","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/tools/querit.py#L152-L188","documentation":"TypeError raised by the Querit search tool when the parsed JSON body of the Querit search API response is not a JSON object (dict) — e.g. the endpoint returned a JSON array, string, number, or null. It is the first of three shape checks applied to response_data before results are extracted.","triggerScenarios":"Querit API replying with a bare JSON array (e.g. a legacy /results endpoint), an HTML error page that happened to parse as a JSON scalar, or a proxy returning 'null' on a 502. Any self._search() return value where isinstance(response_data, dict) is False triggers it.","commonSituations":"Querit backend version drift changing the response envelope from {\"results\": ...} to a top-level list; API gateways converting errors into JSON strings like \"Service Unavailable\"; mocking the endpoint in tests with json=[...] instead of json={...}.","solutions":["Replay the request with curl and inspect the raw body — confirm it starts with '{'.","If the API now returns a top-level array, wrap or adapt it to the documented {\"results\": {\"result\": [...]}} envelope (or pin the API version you coded against).","If the body is an HTML/text error from a gateway, fix the upstream failure (502/503) rather than the client.","In tests, fix fixtures/mocks to return an object literal."],"exampleFix":"# before (mock returning an array)\nresponses.add(responses.POST, \"https://api.querit.com/search\", json=[{\"title\": \"x\"}])\n\n# after\nresponses.add(responses.POST, \"https://api.querit.com/search\", json={\"results\": {\"result\": [{\"title\": \"x\"}]}})","handlingStrategy":"type-guard","validationCode":"import json\nfrom typing import Any\ndef querit_search_response_ok(body: str) -> bool:\n    try:\n        data = json.loads(body)\n    except json.JSONDecodeError:\n        return False\n    return isinstance(data, dict)","typeGuard":"def is_querit_search_payload(v: Any) -> bool:\n    return (\n        isinstance(v, dict)\n        and isinstance(v.get(\"results\", {}), dict)\n        and isinstance(v[\"results\"].get(\"result\", []), list)\n    )","tryCatchPattern":"try:\n    out = querit_search._invoke(query=q)\nexcept TypeError as e:\n    if \"JSON object\" in str(e):\n        log.error(\"Querit contract violation: %s\", e); raise\n    raise","preventionTips":["Contract-test the Querit search endpoint shape in CI (jsonschema) so envelope drift is caught before deploy.","Keep mocks/fixtures typed as dicts mirroring the documented schema.","Wrap responses in an adapter that asserts the shape once at the boundary."],"tags":["api","json","response-validation","querit"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}