{"record":{"id":"bcac767de2f3da1f","repo":"deepset-ai/haystack","slug":"input-must-be-a-dictionary-or-a-list-of-dictionari","errorCode":null,"errorMessage":"Input must be a dictionary or a list of dictionaries.","messagePattern":"Input must be a dictionary or a list of dictionaries\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"haystack/components/validators/json_schema.py","lineNumber":252,"sourceCode":"            new_dict = {}\n            for key, value in data.items():\n                if isinstance(value, str):\n                    try:\n                        json_value = json.loads(value)\n                        if isinstance(json_value, (dict, list)):\n                            new_dict[key] = self._recursive_json_to_object(json_value)\n                        else:\n                            new_dict[key] = value  # Preserve the original string value\n                    except json.JSONDecodeError:\n                        new_dict[key] = value\n                elif isinstance(value, dict):\n                    new_dict[key] = self._recursive_json_to_object(value)\n                else:\n                    new_dict[key] = value\n            return new_dict\n\n        # If it's neither a list nor a dictionary, return the value directly\n        raise ValueError(\"Input must be a dictionary or a list of dictionaries.\")\n","sourceCodeStart":234,"sourceCodeEnd":253,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/components/validators/json_schema.py#L234-L253","documentation":"JsonSchemaValidator's internal _recursive_json_to_object recursively converts JSON strings embedded in dict values into objects. It only accepts a dict or a list at the top level (dicts and lists are recursed; scalars inside dicts are preserved). Passing any other top-level value (str, int, None, etc.) hits the terminal raise ValueError.","triggerScenarios":"Calling JsonSchemaValidator.run with a `json` input that is a bare JSON string, a scalar, or None, instead of a dict or list of dicts. This happens when an upstream LLM component emits the raw string rather than a parsed dict, or when a template/wire step yields None.","commonSituations":"LLM completion text not parsed to JSON before validation; a generator/extractor component outputs a string; pipeline wiring passes a ChatMessage content string directly; JSON string was json.loads'd at one level but the top-level value remained a string (double-encoded JSON).","solutions":["Parse the input before validation: if isinstance(data, str): data = json.loads(data) before calling JsonSchemaValidator.run.","Ensure the LLM output is converted to dict/list (e.g. via an output adapter or JSONOutputParser) before the validator.","If data may be None (e.g. failed generation), check and provide a fallback dict before run().","Check that double-encoded JSON isn't the issue: json.loads may need to be applied twice for nested stringified JSON."],"exampleFix":"// before\nresult = validator.run(json=llm_output_text)\n// after\nif isinstance(llm_output_text, str):\n    llm_output_text = json.loads(llm_output_text)\nresult = validator.run(json=llm_output_text)","handlingStrategy":"validation","validationCode":"def is_valid_validator_input(data) -> bool:\n    return isinstance(data, (dict, list)) and not (isinstance(data, list) and any(not isinstance(i, dict) for i in data))\n# guard: if isinstance(data, str): data = json.loads(data)","typeGuard":"def is_dict_or_dict_list(data: Any) -> TypeGuard[dict | list[dict]]:\n    if isinstance(data, dict):\n        return True\n    return isinstance(data, list) and all(isinstance(i, dict) for i in data)","tryCatchPattern":"try:\n    result = validator.run(json=data)\nexcept ValueError as e:\n    if \"Input must be a dictionary\" in str(e):\n        data = json.loads(data) if isinstance(data, str) else {}\n        result = validator.run(json=data)","preventionTips":["Always json.loads LLM string output before JsonSchemaValidator","Check for None from upstream components before validation","Beware double-encoded JSON strings (loads may need two passes)","Type-annotate pipeline connections so non-dict outputs can't be wired to the validator"],"tags":["haystack","json-schema","validation","type-error"],"backgroundTag":"invalid-json-input","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}