{"record":{"id":"7088a5ac664f3cfc","repo":"zylon-ai/private-gpt","slug":"invalid-system-item-in-list-dict-item","errorCode":null,"errorMessage":"Invalid system item in list (dict): {item}","messagePattern":"Invalid system item in list \\(dict\\): (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/chat/input_models.py","lineNumber":208,"sourceCode":"        except Exception as e:\n            raise ValueError(f\"Invalid system specification (dict): {system}\") from e\n\n    # List: allow list of System / str / dict and convert+merge\n    if isinstance(system, list):\n        # Convert each item to System\n        converted: list[System] = []\n        for item in system:\n            if isinstance(item, System):\n                converted.append(item)\n            elif isinstance(item, TextBlock):\n                converted.append(System(text=item.text))\n            elif isinstance(item, str):\n                converted.append(System(text=item))\n            elif isinstance(item, dict):\n                try:\n                    converted.append(System.model_validate(item))\n                except Exception as e:\n                    raise ValueError(\n                        f\"Invalid system item in list (dict): {item}\"\n                    ) from e\n            else:\n                raise ValueError(f\"Invalid system item in list: {item}\")\n\n        if not converted:\n            return System()\n\n        # Merge converted System objects into a single System\n        potential_system = converted[0]\n        for item in converted[1:]:\n            merged_text = None\n            if potential_system.text or item.text:\n                # concatenate texts with newline when both present\n                if potential_system.text and item.text:\n                    merged_text = f\"{potential_system.text}\\n{item.text}\"\n                else:\n                    merged_text = potential_system.text or item.text","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/chat/input_models.py#L190-L226","documentation":"Raised by the /convert endpoint (convert_content) when the request body specifies an explicit reader that is not registered for the file's extension. The ReaderRegistry maps extensions to a set of available reader names; a mismatch between the requested reader and the extension's registry entry yields this 422 Unprocessable Entity.","triggerScenarios":"POST /ingest/convert (or equivalent) with body.reader set to a name that exists for a different extension or not at all, while the input filename extension resolves via get_extension(). E.g. sending reader='pymupdf' for a .csv input where only readers registered for csv are valid.","commonSituations":"Hardcoding a reader name across file types after a version upgrade renamed readers; copy-pasting a curl example with a reader from another extension; a reader plugin not installed (e.g. its optional dependency missing) so it never registers.","solutions":["Omit body.reader to let the service auto-select the default reader for the extension.","Call the registry (or check the error's 'Valid readers' list) and use one of the names it reports for that extension.","If a specific reader is expected but absent, install its optional dependency / enable the component so it registers."],"exampleFix":"# before\nPOST /ingest/convert\n{\"input\": {...csv...}, \"reader\": \"pymupdf\"}\n\n# after\nPOST /ingest/convert\n{\"input\": {...csv...}}   # reader omitted -> auto-selected\n# or\n{\"input\": {...csv...}, \"reader\": \"pandas_csv\"}  # a name from registry.get_reader_names('.csv')","handlingStrategy":"validation","validationCode":"// Fetch valid readers for the extension before requesting\nconst valid = await api.readerNames(extension); // or cache from docs\nif (reader && !valid.includes(reader)) reader = undefined; // let server pick","typeGuard":"const readerIsValid = (reader, valid) => valid.includes(reader);","tryCatchPattern":"try { await api.convert({ input, reader }); }\ncatch (e) {\n  if (e.status === 422 && /not supported/.test(e.detail)) {\n    return api.convert({ input }); // retry without explicit reader\n  }\n  throw e;\n}","preventionTips":["Default to omitting reader and let the server choose","Pin reader names only after checking registry.get_reader_names() for the exact extension","After upgrades, re-verify hardcoded reader names still exist"],"tags":["fastapi","http-422","ingestion","document-readers","validation"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}