{"record":{"id":"b090731afee69850","repo":"microsoft/graphrag","slug":"response-must-be-a-list-of-dictionaries","errorCode":null,"errorMessage":"Response must be a list of dictionaries.","messagePattern":"Response must be a list of dictionaries\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/graphrag/graphrag/query/structured_search/drift_search/search.py","lineNumber":157,"sourceCode":"            intermediate_answer = \"\\n\\n\".join([\n                i[\"intermediate_answer\"] for i in response if \"intermediate_answer\" in i\n            ])\n\n            follow_ups = [fu for i in response for fu in i.get(\"follow_up_queries\", [])]\n\n            if not follow_ups:\n                error_msg = \"No follow-up queries found in primer response. Ensure that the primer response includes follow-up queries.\"\n                raise RuntimeError(error_msg)\n\n            score = sum(i.get(\"score\", float(\"-inf\")) for i in response) / len(response)\n            response_data = {\n                \"intermediate_answer\": intermediate_answer,\n                \"follow_up_queries\": follow_ups,\n                \"score\": score,\n            }\n            return DriftAction.from_primer_response(query, response_data)\n        error_msg = \"Response must be a list of dictionaries.\"\n        raise ValueError(error_msg)\n\n    async def _search_step(\n        self,\n        global_query: str,\n        k_followups: int,\n        search_engine: LocalSearch,\n        actions: list[DriftAction],\n    ) -> list[DriftAction]:\n        \"\"\"\n        Perform an asynchronous search step by executing each DriftAction asynchronously.\n\n        Args:\n            global_query (str): The global query for the search.\n            search_engine (LocalSearch): The local search engine instance.\n            actions (list[DriftAction]): A list of actions to perform.\n\n        Returns\n        -------","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/microsoft/graphrag/blob/f40e9a26ce62ba0b3fef8837d24aafdcc6e6c704/packages/graphrag/graphrag/query/structured_search/drift_search/search.py#L139-L175","documentation":"DRIFT search expects the primer LLM response, once parsed, to be a list of dictionaries (one per community report with intermediate_answer, follow_up_queries, score). If the parsed response is any other shape, _process_primer_results raises this ValueError because it cannot extract the required fields.","triggerScenarios":"Calling DriftSearch.search where the model returns a single JSON object, a bare string, or nested/escaped JSON instead of a list of objects, causing the branch that builds response_data to be skipped and fall through to the raise at the end of _process_primer_results.","commonSituations":"Local or smaller models wrapping output in markdown fences or returning one merged object, custom prompt tweaks that change the output format, or JSON parsing configured to yield a non-list root (e.g. {'reports': [...]} instead of [...]).","solutions":["Use a model that reliably returns a JSON array of objects as instructed","If you modified the primer prompt or JSON parsing, ensure the root of the parsed response is a list of dicts (unwrap it before passing to DRIFT)","Retry with a stronger model or lower temperature for more format-compliant output","Log the raw response to see what shape the model actually returned and adjust parsing accordingly"],"exampleFix":"# before (custom parse returning a wrapped object)\nresponse = json.loads(raw)  # {'reports': [{...}, ...]}\n\n# after\nresponse = json.loads(raw)\nif isinstance(response, dict):\n    response = response.get('reports', [response])","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def is_primer_response_list(response) -> bool:\n    return isinstance(response, list) and all(isinstance(i, dict) for i in response)","tryCatchPattern":"try:\n    result = await drift_search.aresolve(query)\nexcept ValueError as e:\n    if \"Response must be a list of dictionaries\" in str(e):\n        # model returned wrong shape; retry or preprocess the response\n        ...\n    raise","preventionTips":["Use models that reliably emit JSON arrays; wrap fenced JSON before parsing","If you intercept/parse the primer LLM output yourself, normalize the root to a list of dicts before it reaches DRIFT","Add retry logic for format errors — shape mistakes from LLMs are transient"],"tags":["graphrag","drift-search","response-format","type-validation"],"backgroundTag":"llm-output-parsing-failed","analyzedSha":"f40e9a26ce62ba0b3fef8837d24aafdcc6e6c704","analyzedAt":"2026-08-27T11:16:29.677Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}