{"record":{"id":"c4cd645845933b5a","repo":"zylon-ai/private-gpt","slug":"conflict-setting-environment-variable-for-model-m","errorCode":null,"errorMessage":"Conflict setting environment variable for model {model_id}: {env_key}. Parameter '{key}' is already set as a scalar value.","messagePattern":"Conflict setting environment variable for model (.+?): (.+?)\\. Parameter '(.+?)' is already set as a scalar value\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/settings/settings_loader.py","lineNumber":127,"sourceCode":"        - Each model automatically gets a \"name\" field with its ID\n    \"\"\"\n    models = {}\n\n    def _set_nested_param(\n        config: dict[str, Any],\n        param_keys: list[str],\n        value: str,\n        model_id: str,\n        env_key: str,\n    ) -> None:\n        \"\"\"Set a nested parameter value, creating intermediate dictionaries.\"\"\"\n        current = config\n\n        for key in param_keys[:-1]:\n            if key not in current:\n                current[key] = {}\n            elif not isinstance(current[key], dict):\n                raise ValueError(\n                    f\"Conflict setting environment variable for model {model_id}: {env_key}. \"\n                    f\"Parameter '{key}' is already set as a scalar value.\"\n                )\n            current = current[key]\n\n        current[param_keys[-1]] = value\n\n    for key, value in environ.items():\n        if key.startswith(\"PGPT_MODELS_\") and key.count(\"_\") >= 3:\n            _, _, model_id, param = key.split(\"_\", 3)\n\n            model_id = model_id.lower()\n            if model_id not in models:\n                models[model_id] = {\"name\": model_id}\n\n            param_lower = param.lower()\n            param_keys = param_lower.split(\"__\")\n","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/settings/settings_loader.py#L109-L145","documentation":"Raised by discover_models_from_environment while flattening PGPT_MODELS_* environment variables into nested model config dicts. Double underscores in a parameter name create nested dicts (PGPT_MODELS_CLAUDE_CONFIG__TEMPERATURE -> {'config': {'temperature': ...}}). If one variable already set an intermediate path segment to a scalar string and a later variable tries to descend through that same segment as a dict, the scalar blocks dictionary creation and this ValueError fires.","triggerScenarios":"Defining both PGPT_MODELS_GPT4_CONFIG=abc and PGPT_MODELS_GPT4_CONFIG__TEMPERATURE=0.7 (CONFIG is first a scalar, then needs to be a dict); any pair of PGPT_MODELS_<ID>_<PARAM> variables where one param name is a prefix of another param's double-underscore path, e.g. ..._OPTIONS_X after ..._OPTIONS=y; conflicts inside a .env file loaded into the environment.","commonSituations":"Incrementally adding tuning env vars to a docker-compose file and accidentally reusing a parameter name as a nesting level; copy-pasting model config from docs that mixes flat and nested styles; a CI environment leaking a stale PGPT_MODELS_* variable that collides with a new one.","solutions":["Rename the scalar variable so it is not also used as a nested prefix (e.g. PGPT_MODELS_GPT4_OPTIONS_LABEL=x instead of PGPT_MODELS_GPT4_OPTIONS=x)","Or convert the scalar into a nested value: replace PGPT_MODELS_GPT4_CONFIG=abc with PGPT_MODELS_GPT4_CONFIG__VALUE=abc","List all colliding vars: env | grep '^PGPT_MODELS_' and remove the stale one (often from .env, compose file, or CI secrets)","If both values are genuinely needed, move one into settings.yaml instead of environment discovery"],"exampleFix":"# before (conflict: OPTIONS is scalar and also a nesting key)\nPGPT_MODELS_GPT4_OPTIONS=low\nPGPT_MODELS_GPT4_OPTIONS__TEMPERATURE=0.7\n\n# after\nPGPT_MODELS_GPT4_OPTIONS__LEVEL=low\nPGPT_MODELS_GPT4_OPTIONS__TEMPERATURE=0.7","handlingStrategy":"validation","validationCode":"import os, collections\n\ndef find_model_env_conflicts() -> list[str]:\n    paths: dict[str, str] = {}  # \"model_id.param.path\" -> env var\n    conflicts: list[str] = []\n    for key in os.environ:\n        if key.startswith(\"PGPT_MODELS_\") and key.count(\"_\") >= 3:\n            _, _, mid, param = key.split(\"_\", 3)\n            parts = param.lower().split(\"__\")\n            for i in range(1, len(parts)):\n                prefix = mid.lower() + \".\" + \".\".join(parts[:i])\n                if prefix in paths and paths[prefix] != key:\n                    conflicts.append(f\"{paths[prefix]} vs {key} ({prefix})\")\n            full = mid.lower() + \".\" + \".\".join(parts)\n            paths.setdefault(full, key)\n    return conflicts","typeGuard":"null","tryCatchPattern":"try:\n    models = discover_models_from_environment(dict(os.environ))\nexcept ValueError as e:\n    # message names the conflicting env key; drop/rename it and retry\n    raise SystemExit(str(e)) from e","preventionTips":["Never use the same parameter segment both as a leaf and as a nesting prefix in PGPT_MODELS_* names","Keep all model env vars in one .env file so collisions are greppable: grep 'PGPT_MODELS_' .env","Run discovery explicitly at deploy time so conflicts surface before the server boots","Document the __-nesting convention for anyone adding new model variables"],"tags":["configuration","environment-variables","models","conflict"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}