zylon-ai/private-gpt · error · ValueError
must be a list or comma-separated string
Error message
must be a list or comma-separated string
What it means
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.
Source
Thrown at private_gpt/settings/settings.py:1641
default_factory=lambda: ["authorization", "x-api-key"],
description="HTTP request headers to capture in the Principal. "
"When set via env var, use a comma-separated string: "
"'authorization, x-custom-header'.",
)
forwarded_cookies: list[str] = Field(
default_factory=list,
description="HTTP request cookies to capture in the Principal. "
"When set via env var, use a comma-separated string: "
"'session, csrf-token'.",
)
@field_validator("forwarded_headers", "forwarded_cookies", mode="before")
@classmethod
def _parse_list(cls, value: object) -> list[str]:
if isinstance(value, str):
return [h.strip().lower() for h in value.split(",") if h.strip()]
if not isinstance(value, list):
raise ValueError("must be a list or comma-separated string")
return [str(h).strip().lower() for h in value if h]
class BashSettings(BaseModel):
cpu_limit_seconds: int = Field(
default=30,
description="RLIMIT_CPU applied to each isolated bash subprocess.",
)
memory_limit_mb: int = Field(
default=512,
description="RLIMIT_AS in MB applied to each isolated bash subprocess.",
)
fsize_limit_mb: int = Field(
default=50,
description="RLIMIT_FSIZE in MB applied to each isolated bash subprocess.",
)
nproc_limit: int = Field(
default=50,View on GitHub (pinned to 4a030776a3)
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.
Example fix
# before (settings.yaml) forwarded_headers: x-forwarded-for: true # parses as dict -> error # after forwarded_headers: - x-forwarded-for - x-request-id
Defensive patterns
Strategy: type-guard
Validate before calling
def parse_listlike(value):
if isinstance(value, str):
return [h.strip().lower() for h in value.split(',') if h.strip()]
if isinstance(value, list):
return [str(h).strip().lower() for h in value if h]
raise ValueError('must be a list or comma-separated string') Type guard
const isListOrCsv = (v: unknown): v is string | string[] => typeof v === 'string' || Array.isArray(v);
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Token limit must be set and greater than 0.
- 'oneOf' must be an array of schemas
- 'anyOf' must be an array of schemas
- 'allOf' must be an array of schemas
- Schema must define a 'type' field
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/4c1be8c8b8f29484.
Report an issue: GitHub.