Skip to content

fix(bundler): reject a top-level non-mapping bundle-catalogs.yml in _merge_config#3659

Open
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/bundler-catalog-toplevel-mapping-guard
Open

fix(bundler): reject a top-level non-mapping bundle-catalogs.yml in _merge_config#3659
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/bundler-catalog-toplevel-mapping-guard

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

What

_merge_config silently ignored a top-level non-mapping bundle-catalogs.yml (a YAML list or scalar): data.get("catalogs") if isinstance(data, dict) else None made a list/scalar document fall through to None → early return → the built-in default stack, with no error.

The sibling reader of the same filecommands_impl/catalog_config._read — raises "expected a mapping at the top level" for exactly those documents. Merged PR #3623 already made the inner non-list catalogs value agree between the two readers; this closes the remaining top-level-shape gap so both readers reject the same malformed input.

Fix

Add an explicit top-level mapping guard mirroring _read:

if not isinstance(data, dict):
    raise BundlerError(f"Malformed catalog config at {config_path}: expected a mapping at the top level, got {type(data).__name__}.")

An empty file (load_yaml coerces to {}), absent catalogs, and catalogs: [] all remain no-ops.

Tests

tests/contract/test_catalog_schema.py::test_toplevel_non_mapping_raises (parametrized over a top-level list and a scalar) — both raise after the fix, silently return the default stack before it. Regression tests confirm absent/empty catalogs still yield the built-in defaults. ruff clean; all 23 contract tests pass.


AI-assisted: authored with Claude Code. Verified the message/behavior matches the _read sibling and confirmed fail-before/pass-after.

…merge_config

_merge_config silently ignored a top-level non-mapping document (a YAML list
or scalar) — `data.get("catalogs") if isinstance(data, dict) else None` made
it fall through to the built-in default stack — while the sibling reader of
the SAME file (commands_impl/catalog_config._read) raises "expected a mapping
at the top level". github#3623 already made the inner non-list `catalogs` value
agree between the two readers; this closes the remaining top-level-shape gap
so both readers reject the same malformed documents.

An empty file (load_yaml coerces to {}), absent `catalogs`, and `catalogs: []`
all remain no-ops.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jawwad-ali
jawwad-ali requested a review from mnriem as a code owner July 22, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant