{"record":{"id":"6ed59744af183720","repo":"zylon-ai/private-gpt","slug":"config-file-has-no-top-level-mapping-path","errorCode":null,"errorMessage":"Config file has no top-level mapping: {path}","messagePattern":"Config file has no top-level mapping: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"critical","filePath":"private_gpt/settings/settings_loader.py","lineNumber":66,"sourceCode":"\ndef load_settings_from_profile(profile: str) -> dict[str, Any]:\n    if profile == \"default\":\n        profile_file_name = \"settings.yaml\"\n    elif profile == \"override\":\n        profile_file_name = \"settings.override.yaml\"\n    else:\n        profile_file_name = f\"settings-{profile}.yaml\"\n\n    config: dict[str, Any] = {}\n    found = False\n    for settings_folder in _settings_folders:\n        path = Path(settings_folder) / profile_file_name\n        if not path.is_file():\n            continue\n        with Path(path).open(\"r\") as f:\n            raw = load_yaml_with_envvars(f)\n        if not isinstance(raw, dict):\n            raise TypeError(f\"Config file has no top-level mapping: {path}\")\n        config = raw\n        found = True\n        break\n\n    if not found:\n        raise FileNotFoundError(\n            f\"Settings file not found for profile '{profile}'. \"\n            f\"Searched in folders: {_settings_folders} with file name '{profile_file_name}'\"\n        )\n\n    return config\n\n\n@typing.no_type_check\ndef discover_models_from_environment(\n    environ: dict[str, Any] = os.environ,\n) -> list[dict[str, Any]]:\n    \"\"\"Discover model configurations from environment variables.","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/settings/settings_loader.py#L48-L84","documentation":"TypeError raised by the settings loader when a located profile YAML (e.g. settings.yaml or settings-<profile>.yaml) parses to a non-dict root — the entire file must be a top-level mapping because each key becomes a settings section. A YAML file containing only a list, a scalar, or multiple bare documents produces this.","triggerScenarios":"Running with profile P where settings-P.yaml contains a top-level JSON/YAML list or plain string (e.g. a file that is just '- key: value' bullets, or a log dump); a YAML file whose first key is unindented under a list item; multiple '---' documents where the first is a scalar; an empty comment-only file is usually fine (None) but stray text is not.","commonSituations":"Hand-editing settings files and losing the top-level keys; converting config via a script that emitted a list of dicts; truncation/merge tools appending content that changes the root node; wrong file placed in a settings folder that the loader scans.","solutions":["Open the named path from the error and make the root a mapping: every setting must live under top-level keys (e.g. `llm:`, `ui:`, `scheduler:`).","Remove stray list markers or leading documents so `yaml.safe_load(f)` returns a dict.","Validate locally: `python -c \"import yaml,sys; print(type(yaml.safe_load(open('settings.yaml'))))\"` must print <class 'dict'>.","If multiple configs were concatenated, split them into per-profile files."],"exampleFix":"# before (settings-dev.yaml)\n- llm:\n    mode: local\n# after (settings-dev.yaml)\nllm:\n  mode: local","handlingStrategy":"validation","validationCode":"import yaml\n\ndef settings_file_is_mapping(path: str) -> bool:\n    with open(path) as f:\n        return isinstance(yaml.safe_load(f), dict)","typeGuard":"const isMapping = (v: unknown): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":null,"preventionTips":["Run `python -c \"import yaml; assert isinstance(yaml.safe_load(open('settings.yaml')), dict)\"` after editing settings.","Use YAML schema validation (e.g. js-yaml + JSON schema) in CI for all profile files.","Never concatenate multiple YAML documents into one settings file."],"tags":["configuration","yaml","settings-loader","startup","profile"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}