{"record":{"id":"de0013e1bce216ae","repo":"zylon-ai/private-gpt","slug":"expected-list-or-dict-with-items-key-got-type","errorCode":null,"errorMessage":"Expected list or dict with 'items' key, got {type(obj)}","messagePattern":"Expected list or dict with 'items' key, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"private_gpt/chat/schema_models.py","lineNumber":353,"sourceCode":"            strict: bool | None = None,\n            extra: ExtraValues | None = None,\n            from_attributes: bool | None = None,\n            context: Any | None = None,\n            by_alias: bool | None = None,\n            by_name: bool | None = None,\n        ) -> Self:\n            \"\"\"Accept array data directly.\"\"\"\n            if isinstance(obj, list):\n                return cls(items=obj)\n            elif isinstance(obj, dict) and \"items\" in obj:\n                return super().model_validate(\n                    obj,\n                    strict=strict,\n                    from_attributes=from_attributes,\n                    context=context,\n                )\n            else:\n                raise ValueError(\n                    f\"Expected list or dict with 'items' key, got {type(obj)}\"\n                )\n\n        @classmethod\n        def model_json_schema(\n            cls,\n            by_alias: bool = True,\n            ref_template: str = DEFAULT_REF_TEMPLATE,\n            schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema,\n            mode: JsonSchemaMode = \"validation\",\n            *,\n            union_format: Literal[\"any_of\", \"primitive_type_array\"] = \"any_of\",\n        ) -> dict[str, Any]:\n            \"\"\"Return the original array schema, not wrapped in object schema.\"\"\"\n            return schema\n\n        model_config = ConfigDict(populate_by_name=True, use_attribute_docstrings=True)\n","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/chat/schema_models.py#L335-L371","documentation":"Raised by the custom model_validate on the dynamic ArrayModel generated from array JSON schemas (create_model_from_json_schema for type=array). The override accepts either a bare Python list (wrapped as items) or a dict containing an \"items\" key; anything else — a string, number, None, or an items-less dict — raises ValueError with the offending type name.","triggerScenarios":"Calling ArrayModel.model_validate(json_string) where json_string is a str like '[1,2]'; model_validate({\"values\": [...]}) (dict without 'items'); model_validate(None) or model_validate(42). Happens when structured chat output is parsed into the dynamically generated array model.","commonSituations":"Feeding raw LLM JSON text responses into model_validate without json.loads; renaming the wrapper key in serialized output (dumping by items alias off); validating objects produced by a different schema.","solutions":["Parse JSON text first, then validate: ArrayModel.model_validate(json.loads(raw)).","Pass a bare list directly: ArrayModel.model_validate([1, 2, 3]) — the override wraps it.","If using the dict form, keep the 'items' key exactly (or the configured alias) — model_dump_json round-trips with it.","Check the reported type in the message ({type(obj)}) to identify what actually arrived."],"exampleFix":"// before\nmodel = ArrayModel.model_validate(raw_llm_output)  # raw is a str\n\n// after\nimport json\nmodel = ArrayModel.model_validate(json.loads(raw_llm_output))","handlingStrategy":"try-catch","validationCode":"import json\n\nif isinstance(data, (str, bytes)):\n    data = json.loads(data)\nif isinstance(data, dict) and \"items\" not in data and \"values\" not in data:\n    data = list(data.values())[0] if len(data) == 1 else data","typeGuard":"def is_array_model_input(obj: object) -> bool:\n    return isinstance(obj, list) or (isinstance(obj, dict) and \"items\" in obj)","tryCatchPattern":"try:\n    model = ArrayModel.model_validate(payload)\nexcept ValueError:\n    parsed = json.loads(payload) if isinstance(payload, str) else payload\n    model = ArrayModel.model_validate(parsed)","preventionTips":["json.loads LLM JSON output before model_validate.","Round-trip with model_dump_json/model_validate pairs from the same generated model.","Check the reported type in the message to identify the mismatch."],"tags":["pydantic","json-parsing","structured-output","validation"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}