github/spec-kit · error · PresetValidationError
Invalid catalog config {config_path}: expected a mapping at
Error message
Invalid catalog config {config_path}: expected a mapping at root, got {type(data).__name__} What it means
The catalog config YAML parsed successfully but the root node is not a mapping (dict). The loader expects a top-level mapping with a 'catalogs' key; anything else (a list, a scalar, a string) is rejected with PresetValidationError.
Source
Thrown at src/specify_cli/presets/__init__.py:4283
Returns:
Ordered list of PresetCatalogEntry objects, or None if file
doesn't exist or contains no valid catalog entries.
Raises:
PresetValidationError: If any catalog entry has an invalid URL,
the file cannot be parsed, or a priority value is invalid.
"""
if not config_path.exists():
return None
try:
data = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
except (yaml.YAMLError, OSError, UnicodeError) as e:
raise PresetValidationError(
f"Failed to read catalog config {config_path}: {e}"
)
if not isinstance(data, dict):
raise PresetValidationError(
f"Invalid catalog config {config_path}: expected a mapping at root, got {type(data).__name__}"
)
catalogs_data = data.get("catalogs", [])
if not catalogs_data:
return None
if not isinstance(catalogs_data, list):
raise PresetValidationError(
f"Invalid catalog config: 'catalogs' must be a list, got {type(catalogs_data).__name__}"
)
entries: List[PresetCatalogEntry] = []
for idx, item in enumerate(catalogs_data):
if not isinstance(item, dict):
raise PresetValidationError(
f"Invalid catalog entry at index {idx}: expected a mapping, got {type(item).__name__}"
)
url = str(item.get("url", "")).strip()
if not url:
continueView on GitHub (pinned to bf88c9f9a8)
Solutions
- Wrap the entries under a top-level 'catalogs:' key so the root is a mapping
- Remove any stray top-level scalar or multi-document separators (---) that change the root type
- Re-check with 'python -c "import yaml; print(type(yaml.safe_load(open('<file>'))))"' — it must print <class 'dict'>
Example fix
# before
- url: https://example.com/catalog.json
priority: 1
# after
catalogs:
- url: https://example.com/catalog.json
priority: 1 Defensive patterns
Strategy: validation
Validate before calling
data = yaml.safe_load(path.read_text(encoding="utf-8"))
if not isinstance(data, dict):
raise ValueError(f"catalog config root must be a mapping, got {type(data).__name__}") Type guard
def is_catalog_config_root(data: object) -> bool:
return isinstance(data, dict) Try / catch
try:
catalogs = manager.load_catalog_config(path)
except PresetValidationError as e:
if "expected a mapping at root" in str(e):
fix_config_root_shape(path) # or report to user
raise Prevention
- Start from the documented template that has 'catalogs:' at the root
- Validate config shape (root mapping + catalogs list) in a preflight check
When it happens
Trigger: Catalog config file whose root is a YAML list ('- url: ...' at top level), a plain scalar, or a multi-document stream where safe_load returns a non-dict. Encountered when loading the preset catalog config.
Common situations: User writes the catalog entries as a top-level list instead of nesting them under 'catalogs:'; user pastes example content that is a bare string; converting config from another format drops the mapping wrapper.
Related errors
- Invalid catalog config: 'catalogs' must be a list, got {type
- Invalid catalog entry at index {idx}: expected a mapping, go
- Malformed catalog config at {path}: expected a mapping at th
- Malformed catalog config at {config_path}: expected a mappin
- Malformed catalog config at {config_path}: 'catalogs' must b
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/86b98cd7ddac766e.
Report an issue: GitHub.