github/spec-kit · error · BundlerError

Preset '{component.id}' is from a discovery-only catalog; in

Error message

Preset '{component.id}' is from a discovery-only catalog; installation is not allowed.

What it means

The preset was found in a catalog, but the catalog entry carries _install_allowed=False, marking it as discovery-only. The bundler honors that flag and refuses to install it as part of a bundle, before doing any version comparison or download.

Source

Thrown at src/specify_cli/bundler/services/primitives.py:202

                bundled, speckit_version, priority, **({"force": True} if force else {})
            )
            return

        if not self._allow_network:
            raise BundlerError(
                f"Preset '{component.id}' is not bundled and network access is "
                f"disabled; re-run without --offline or install it first with "
                f"'specify preset add {component.id}'."
            )

        from ...presets import PresetCatalog

        catalog = PresetCatalog(self._root)
        info = catalog.get_pack_info(component.id)
        if not info:
            raise BundlerError(f"Preset '{component.id}' not found in any catalog.")
        if not info.get("_install_allowed", True):
            raise BundlerError(
                f"Preset '{component.id}' is from a discovery-only catalog; "
                "installation is not allowed."
            )
        _assert_pinned_version(
            "Preset", component.id, component.version, info.get("version")
        )
        zip_path = catalog.download_pack(component.id)
        try:
            self._manager.install_from_zip(
                zip_path, speckit_version, priority, **({"force": True} if force else {})
            )
        finally:
            with contextlib.suppress(Exception):
                if zip_path.exists():
                    zip_path.unlink()

    def remove(self, component: ComponentRef) -> None:
        try:

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Find the installable source for that preset (its real registry or repository) and either install it directly with `specify preset add <id> --catalog <source>` or vendor it into the bundle.
  2. Remove the preset from bundle.yml if it cannot be installed.
  3. Check the catalog's documentation — discovery-only entries usually name where the content actually lives.
Defensive patterns

Strategy: validation

Validate before calling

from specify_cli.presets import PresetCatalog

info = PresetCatalog(project_root).get_pack_info(component_id)
if info and not info.get("_install_allowed", True):
    print(f"{component_id} is discovery-only; find an installable source or vendor it")

Try / catch

from specify_cli.bundler.core import BundlerError

try:
    install_bundle(project_root, plan, installer)
except BundlerError as exc:
    if "discovery-only catalog" in str(exc):
        switch_component_to_installable_source(plan)

Prevention

When it happens

Trigger: A bundle manifest referencing a preset listed in a read-only/discovery catalog (e.g. an index of external or curated content that is not installable from that source). get_pack_info() returned info, but info['_install_allowed'] was falsy.

Common situations: Curated indexes that only point at third-party sites; corporate catalogs listing available presets without hosting them; bundle authors copying an id out of a discovery listing without checking its install source.

Related errors


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