zylon-ai/private-gpt · critical · TypeError
Config file has no top-level mapping: {path}
Error message
Config file has no top-level mapping: {path} What it means
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.
Source
Thrown at private_gpt/settings/settings_loader.py:66
def load_settings_from_profile(profile: str) -> dict[str, Any]:
if profile == "default":
profile_file_name = "settings.yaml"
elif profile == "override":
profile_file_name = "settings.override.yaml"
else:
profile_file_name = f"settings-{profile}.yaml"
config: dict[str, Any] = {}
found = False
for settings_folder in _settings_folders:
path = Path(settings_folder) / profile_file_name
if not path.is_file():
continue
with Path(path).open("r") as f:
raw = load_yaml_with_envvars(f)
if not isinstance(raw, dict):
raise TypeError(f"Config file has no top-level mapping: {path}")
config = raw
found = True
break
if not found:
raise FileNotFoundError(
f"Settings file not found for profile '{profile}'. "
f"Searched in folders: {_settings_folders} with file name '{profile_file_name}'"
)
return config
@typing.no_type_check
def discover_models_from_environment(
environ: dict[str, Any] = os.environ,
) -> list[dict[str, Any]]:
"""Discover model configurations from environment variables.View on GitHub (pinned to 4a030776a3)
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.
Example fix
# before (settings-dev.yaml)
- llm:
mode: local
# after (settings-dev.yaml)
llm:
mode: local Defensive patterns
Strategy: validation
Validate before calling
import yaml
def settings_file_is_mapping(path: str) -> bool:
with open(path) as f:
return isinstance(yaml.safe_load(f), dict) Type guard
const isMapping = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Default model '{self._default_model_id}' not found in regist
- Settings file not found for profile '{profile}'. Searched in
- Environment variable {env_var} is not set and not default wa
- Default LLM model '{model_id}' could not be initialized: {e}
- No model specified and no models are configured
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/6ed59744af183720.
Report an issue: GitHub.