{"record":{"id":"66602917017bb12c","repo":"zylon-ai/private-gpt","slug":"anyof-must-be-an-array-of-schemas","errorCode":null,"errorMessage":"'anyOf' must be an array of schemas","messagePattern":"'anyOf' must be an array of schemas","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/chat/schema_models.py","lineNumber":102,"sourceCode":"def _validate_json_schema_item(schema: dict[str, Any], strict: bool = True) -> None:\n    \"\"\"Validate that the schema is a valid JSON Schema object.\"\"\"\n    if not isinstance(schema, dict):\n        raise ValueError(\"Schema must be a dictionary representing JSON Schema\")\n\n    if schema == {}:\n        return\n\n    # Handle combinators first\n    if \"oneOf\" in schema:\n        if not isinstance(schema[\"oneOf\"], list):\n            raise ValueError(\"'oneOf' must be an array of schemas\")\n        for sub_schema in schema[\"oneOf\"]:\n            _validate_json_schema_item(sub_schema, strict=False)\n        return  # oneOf schemas don't need type field\n\n    if \"anyOf\" in schema:\n        if not isinstance(schema[\"anyOf\"], list):\n            raise ValueError(\"'anyOf' must be an array of schemas\")\n        for sub_schema in schema[\"anyOf\"]:\n            _validate_json_schema_item(sub_schema, strict=False)\n        return  # anyOf schemas don't need type field\n\n    if \"allOf\" in schema:\n        if not isinstance(schema[\"allOf\"], list):\n            raise ValueError(\"'allOf' must be an array of schemas\")\n        for sub_schema in schema[\"allOf\"]:\n            _validate_json_schema_item(sub_schema, strict=False)\n        return  # allOf schemas don't need type field\n\n    # Regular schema validation\n    if \"type\" not in schema:\n        if strict:\n            raise ValueError(\"Schema must define a 'type' field\")\n        else:\n            return  # Non-strict mode allows missing type\n","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/chat/schema_models.py#L84-L120","documentation":"Pydantic field-validator error on SkillFile.path when the value contains a backslash. Skill file paths must use '/' as the sole separator (canonical, cross-platform form); Windows-style paths are rejected with this ValueError and FastAPI returns 422.","triggerScenarios":"Submitting a skill file entry with path 'assets\\\\logo.png' — typically produced on Windows clients or by code using os.path.join and then serializing without normalization.","commonSituations":"Windows developer machines; Python scripts building paths with os.path.join and passing them verbatim; log/config files containing backslash-separated paths.","solutions":["Normalize with posix semantics: PurePosixPath(*Path(p).parts).as_posix() or p.replace('\\\\', '/').","Build paths with '/' literals or pathlib's as_posix(), never raw os.path.join output.","Validate client-side that path matches ^[^\\\\]+$ before submit."],"exampleFix":"# before\n{\"path\": \"assets\\\\logo.png\", \"content_base64\": \"...\"}\n\n# after\nfrom pathlib import PurePosixPath, Path\npath = PurePosixPath(*Path(raw).parts).as_posix()  # 'assets/logo.png'\n{\"path\": path, \"content_base64\": \"...\"}","handlingStrategy":"validation","validationCode":"const path = String(rawPath).replace(/\\\\/g, '/');\nif (rawPath.includes('\\\\')) warn('normalized backslashes for skill path');","typeGuard":"const usesPosixSeparators = (p) => typeof p === 'string' && !p.includes('\\\\');","tryCatchPattern":null,"preventionTips":["Build skill paths with as_posix() (Python) or '/' joins (JS), never os.path.join output","On Windows, normalize all paths before serializing to the API","Add a unit test that round-trips paths through the validator on Windows CI"],"tags":["pydantic","http-422","validation","skills","windows","path-handling"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}