github/spec-kit · error · BundlerError
Malformed catalog config at {path}: 'catalogs' must be a lis
Error message
Malformed catalog config at {path}: 'catalogs' must be a list, got {type(catalogs).__name__}. What it means
Raised when the `catalogs` key in `bundle-catalogs.yml` is present but not a YAML list. Per the schema (`bundle-catalog.schema.md`) `catalogs` must be an array of source mappings; a mapping or scalar is malformed. `catalogs: null` (or the key absent) is fine and returns an empty list.
Source
Thrown at src/specify_cli/bundler/commands_impl/catalog_config.py:68
f"Malformed catalog config at {path}: expected a mapping at the top "
f"level, got {type(data).__name__}."
)
schema_version = data.get("schema_version")
if schema_version is not None and (
str(schema_version).strip().split(".")[0]
!= CONFIG_SCHEMA_VERSION.split(".")[0]
):
raise BundlerError(
f"Unsupported catalog config schema version "
f"'{str(schema_version).strip()}' at {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):
raise BundlerError(
f"Malformed catalog config at {path}: 'catalogs' must be a list, "
f"got {type(catalogs).__name__}."
)
for entry in catalogs:
if not isinstance(entry, dict):
raise BundlerError(
f"Malformed catalog config at {path}: each catalog entry must be "
f"a mapping, got {type(entry).__name__}."
)
return list(catalogs)
def _write(project_root: Path, catalogs: list[dict]) -> None:
payload = {"schema_version": CONFIG_SCHEMA_VERSION, "catalogs": catalogs}
dump_yaml(_config_path(project_root), payload, within=project_root)
def _slug(value: str) -> str:View on GitHub (pinned to bf88c9f9a8)
Solutions
- Make each source a list item under `catalogs:` (prefix with `- `)
- Validate the YAML with a linter before saving
- Use the CLI add/remove commands instead of manual edits
Example fix
# before
catalogs:
id: community
url: https://example.com/c.json
# after
catalogs:
- id: community
url: https://example.com/c.json Defensive patterns
Strategy: validation
Validate before calling
catalogs = data.get("catalogs")
if catalogs is not None and not isinstance(catalogs, list):
raise SystemExit("'catalogs' must be a list of mappings — each entry starts with '- '") Type guard
def catalogs_is_list(data: dict) -> bool:
c = data.get("catalogs")
return c is None or isinstance(c, list) Try / catch
try:
read_catalog_config(project_root)
except BundlerError as exc:
if "'catalogs' must be a list" in str(exc):
# convert the mapping under catalogs: into list items with '- '
raise
raise Prevention
- Use a YAML linter (yamllint truthy/key-duplicates rules) on .specify/ files
- Remember each entry under catalogs: is a list item prefixed with '- '
When it happens
Trigger: `catalogs:` followed by an indented mapping (`catalogs: id: ...`) instead of list items, or `catalogs: "none"` / any non-list scalar.
Common situations: YAML indentation mistake: writing `id:`/`url:` at the same level under `catalogs:` instead of `- id:` list items; merging configs by hand.
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 {path}: each catalog entry must
- Malformed catalog config at {config_path}: expected a mappin
- Malformed catalog config at {config_path}: 'catalogs' must b
- A catalog url is required.
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/8eda71635a2a518e.
Report an issue: GitHub.