github/spec-kit · error · BundlerError
Malformed catalog config at {config_path}: 'catalogs' must b
Error message
Malformed catalog config at {config_path}: 'catalogs' must be a list, got {type(catalogs).__name__}. What it means
Raised when a bundle-catalogs.yml has a top-level mapping but the 'catalogs' key holds a non-list value (e.g. 'catalogs: 5', 'catalogs: false', 'catalogs: {}', or a string). Only an absent or null 'catalogs' is treated as 'nothing to merge'; every other non-list is malformed. Without this guard, a truthy scalar would crash later with a raw TypeError while falsy non-lists would be silently swallowed.
Source
Thrown at src/specify_cli/bundler/models/catalog.py:312
f"Unsupported catalog config schema version "
f"'{str(schema_version).strip()}' at {config_path}; this Spec Kit "
f"understands version {CONFIG_SCHEMA_VERSION}. The file may have been "
"written by a newer version or is corrupt."
)
catalogs = data.get("catalogs")
if catalogs is None:
return
if not isinstance(catalogs, list):
# Treat only an absent/``None`` ``catalogs`` as "nothing to merge"; any
# other non-list value (``catalogs: 5``, ``false``, ``0``, ``''``,
# ``{}``) is a malformed config and must raise, not be silently skipped
# by a falsy check. Otherwise a truthy scalar would raise a raw
# ``TypeError: 'int' object is not iterable`` from the loop below, while
# falsy non-lists would be swallowed. Report the same actionable
# BundlerError the sibling reader of this file raises
# (commands_impl/catalog_config.py) so both readers of
# bundle-catalogs.yml agree. An empty list stays valid (loop is a no-op).
raise BundlerError(
f"Malformed catalog config at {config_path}: 'catalogs' must be a "
f"list, got {type(catalogs).__name__}."
)
for raw in catalogs:
src = CatalogSource.from_dict(raw, scope)
by_id[src.id] = src
View on GitHub (pinned to bf88c9f9a8)
Solutions
- Change the 'catalogs' value to a YAML list of catalog mappings (each entry starting with '- ').
- If you meant no catalogs, remove the key entirely or set it to null — do not use false/0/''/{}.
- Leave 'catalogs: []' if you want an explicitly empty list.
Example fix
# before (bundle-catalogs.yml)
catalogs:
id: my-catalog
url: https://example.com/catalog.yml
# after
catalogs:
- id: my-catalog
url: https://example.com/catalog.yml Defensive patterns
Strategy: validation
Validate before calling
import yaml
from pathlib import Path
def catalogs_key_is_list(path: Path) -> bool:
data = yaml.safe_load(path.read_text()) or {}
catalogs = data.get("catalogs")
return catalogs is None or isinstance(catalogs, list) Type guard
def is_optional_list(v: object) -> bool:
return v is None or isinstance(v, list) Try / catch
try:
resolve_catalogs(...)
except BundlerError as e:
if "'catalogs' must be a list" in str(e):
# fix the YAML sequence shape, then retry
... Prevention
- Every catalog entry under 'catalogs:' must start with '- '.
- Use 'catalogs: []' or omit the key for empty — never false/0/''/{}.
- Validate with a JSON-Schema description of bundle-catalogs.yml in CI.
When it happens
Trigger: A config file with 'catalogs:' followed by a scalar, mapping, or boolean instead of a YAML sequence is read via _merge_config during bundle search/install. An empty list (catalogs: []) is valid and merges nothing.
Common situations: Writing 'catalogs:' with an inline flow mapping '{...}' instead of a list; forgetting the '-' bullet so a single catalog becomes a mapping; setting 'catalogs: false' while experimenting; hand-merging two config files incorrectly.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Malformed catalog config at {path}: expected a mapping at th
- Malformed catalog config at {config_path}: expected a mappin
- Malformed catalog config at {path}: 'catalogs' must be a lis
- Malformed catalog config at {path}: each catalog entry must
- A catalog url is required.
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/38f7bf911127fe80.
Report an issue: GitHub.