{"record":{"id":"4c1be8c8b8f29484","repo":"zylon-ai/private-gpt","slug":"must-be-a-list-or-comma-separated-string","errorCode":null,"errorMessage":"must be a list or comma-separated string","messagePattern":"must be a list or comma-separated string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/settings/settings.py","lineNumber":1641,"sourceCode":"        default_factory=lambda: [\"authorization\", \"x-api-key\"],\n        description=\"HTTP request headers to capture in the Principal. \"\n        \"When set via env var, use a comma-separated string: \"\n        \"'authorization, x-custom-header'.\",\n    )\n    forwarded_cookies: list[str] = Field(\n        default_factory=list,\n        description=\"HTTP request cookies to capture in the Principal. \"\n        \"When set via env var, use a comma-separated string: \"\n        \"'session, csrf-token'.\",\n    )\n\n    @field_validator(\"forwarded_headers\", \"forwarded_cookies\", mode=\"before\")\n    @classmethod\n    def _parse_list(cls, value: object) -> list[str]:\n        if isinstance(value, str):\n            return [h.strip().lower() for h in value.split(\",\") if h.strip()]\n        if not isinstance(value, list):\n            raise ValueError(\"must be a list or comma-separated string\")\n        return [str(h).strip().lower() for h in value if h]\n\n\nclass BashSettings(BaseModel):\n    cpu_limit_seconds: int = Field(\n        default=30,\n        description=\"RLIMIT_CPU applied to each isolated bash subprocess.\",\n    )\n    memory_limit_mb: int = Field(\n        default=512,\n        description=\"RLIMIT_AS in MB applied to each isolated bash subprocess.\",\n    )\n    fsize_limit_mb: int = Field(\n        default=50,\n        description=\"RLIMIT_FSIZE in MB applied to each isolated bash subprocess.\",\n    )\n    nproc_limit: int = Field(\n        default=50,","sourceCodeStart":1623,"sourceCodeEnd":1659,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/settings/settings.py#L1623-L1659","documentation":"Pydantic field_validator error on the forwarded_headers/forwarded_cookies settings: these fields accept either a list of strings or a single comma-separated string (for env vars), and anything else — a number, dict, boolean, or null-ish scalar — is rejected with 'must be a list or comma-separated string'. Valid string inputs are split, trimmed, and lowercased.","triggerScenarios":"Setting PRIVATE_GPT_*_FORWARDED_HEADERS='session, csrf-token' (OK) versus forwarding a JSON object, a semicolon-separated string, or a bare non-string scalar via YAML/env; YAML unquoted values that parse as other types (e.g. `forwarded_cookies: {a: 1}` or a numeric value); a list containing non-string items is tolerated (str() coerced), but a top-level non-list/non-string is not.","commonSituations":"YAML indentation mistakes turning a list into a nested mapping; env formatters joining with ';' or JSON instead of ','; passing true/false or integers by accident; config generated by templating engines that emit dicts.","solutions":["Use a YAML list: forwarded_headers: [x-forwarded-for, x-request-id].","Or a comma-separated env string: PRIVATE_GPT_*_FORWARDED_HEADERS='session,csrf-token'.","Check YAML indentation — a nested map under the key will parse as a dict and fail.","If templating config, assert the rendered value is either a JSON array or a plain comma-joined string."],"exampleFix":"# before (settings.yaml)\nforwarded_headers:\n  x-forwarded-for: true   # parses as dict -> error\n# after\nforwarded_headers:\n  - x-forwarded-for\n  - x-request-id","handlingStrategy":"type-guard","validationCode":"def parse_listlike(value):\n    if isinstance(value, str):\n        return [h.strip().lower() for h in value.split(',') if h.strip()]\n    if isinstance(value, list):\n        return [str(h).strip().lower() for h in value if h]\n    raise ValueError('must be a list or comma-separated string')","typeGuard":"const isListOrCsv = (v: unknown): v is string | string[] =>\n  typeof v === 'string' || Array.isArray(v);","tryCatchPattern":null,"preventionTips":["Keep these keys as YAML lists in files; use comma-joined strings only for env vars.","Validate rendered config with a JSON schema before deploy.","Beware YAML indentation that turns a list into a nested map."],"tags":["configuration","pydantic","settings","env-vars","validation"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}