github/spec-kit · error · BundlerError

Manifest must be a YAML mapping at the top level.

Error message

Manifest must be a YAML mapping at the top level.

What it means

Raised by BundleManifest.from_dict/from_file when a bundle manifest (bundle.yml) parses to a non-mapping YAML node at the top level. The manifest model requires a mapping so it can extract 'bundle', 'requires', 'integration', 'provides', and 'tags' keys; anything else is structurally unusable.

Source

Thrown at src/specify_cli/bundler/models/manifest.py:97

    @property
    def components(self) -> list[ComponentRef]:
        """All installable component references in deterministic order."""
        return [*self.extensions, *self.presets, *self.steps, *self.workflows]

    # -- construction ---------------------------------------------------------

    @classmethod
    def from_file(cls, path: Path) -> "BundleManifest":
        data = load_yaml(path)
        manifest = cls.from_dict(data)
        manifest.source_path = Path(path)
        return manifest

    @classmethod
    def from_dict(cls, data: Any) -> "BundleManifest":
        if not isinstance(data, dict):
            raise BundlerError("Manifest must be a YAML mapping at the top level.")

        schema_version = _text(data.get("schema_version"))

        bundle_raw = data.get("bundle")
        if not isinstance(bundle_raw, dict):
            raise BundlerError("Manifest is missing the required 'bundle' mapping.")
        meta = BundleMeta(
            id=_text(bundle_raw.get("id")),
            name=_text(bundle_raw.get("name")),
            version=_text(bundle_raw.get("version")),
            role=_text(bundle_raw.get("role")),
            description=_text(bundle_raw.get("description")),
            author=_text(bundle_raw.get("author")),
            license=_text(bundle_raw.get("license")),
        )

        requires_raw = data.get("requires")
        if requires_raw is None:

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Make the manifest's top level a mapping starting with keys like 'schema_version', 'bundle', 'requires'.
  2. Check for accidental '- ' bullets or bare scalars at column 0.
  3. Regenerate the manifest with 'specify bundle' scaffolding if hand-repair is unclear.

Example fix

# before (bundle.yml)
- bundle:
    id: my-bundle

# after
schema_version: 1
bundle:
  id: my-bundle
  name: My Bundle
  version: 1.0.0
  role: library
Defensive patterns

Strategy: validation

Validate before calling

import yaml
from pathlib import Path

def manifest_is_mapping(path: Path) -> bool:
    data = yaml.safe_load(path.read_text())
    return isinstance(data, dict)

Type guard

def is_manifest_mapping(data: object) -> bool:
    return isinstance(data, dict)

Try / catch

from specify_cli.bundler.models.manifest import BundleManifest
try:
    m = BundleManifest.from_file(path)
except BundlerError as e:
    # log path + message; treat bundle as unreadable, skip or fail loudly
    ...

Prevention

When it happens

Trigger: Calling BundleManifest.from_file(path) (directly or via the bundler's install/resolve pipeline) on a bundle.yml whose top level is a list, scalar, or empty-typed value. load_yaml returns the raw parse, and the isinstance(data, dict) guard rejects it.

Common situations: A bundle.yml written as a list of entries; a file that contains only a comment or a stray scalar due to truncation; a generated manifest from a custom bundler that emitted a sequence; copy-paste errors when authoring a bundle.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/76e4e97104e1a46c. Report an issue: GitHub.