github/spec-kit · critical · BundlerError

Downloaded bundle id mismatch: catalog entry {entry.id!r} po

Error message

Downloaded bundle id mismatch: catalog entry {entry.id!r} points to a manifest for {manifest.bundle.id!r}.

What it means

Spec Kit binds a downloaded manifest to the catalog identity that selected it. If catalog entry id and manifest.bundle.id differ, installation stops with BundlerError before any component is applied. This is an integrity/supply-chain guard against a catalog URL that resolves to a different bundle.

Source

Thrown at src/specify_cli/commands/bundle/__init__.py:1073


def _validate_manifest_structure(manifest, *, source: str) -> None:
    """Reject a malformed manifest before any project mutation can occur."""
    from ...bundler.services.validator import validate_manifest

    report = validate_manifest(manifest)
    if report.ok:
        return
    raise BundlerError(
        f"{source} contains an invalid bundle manifest:\n  - "
        + "\n  - ".join(report.errors)
    )


def _validate_catalog_manifest(entry, manifest) -> None:
    """Bind a downloaded manifest to the catalog identity that selected it."""
    if manifest.bundle.id != entry.id:
        raise BundlerError(
            f"Downloaded bundle id mismatch: catalog entry {entry.id!r} points to "
            f"a manifest for {manifest.bundle.id!r}."
        )
    if manifest.bundle.version != entry.version:
        raise BundlerError(
            f"Downloaded bundle version mismatch for {entry.id!r}: catalog declares "
            f"{entry.version!r}, but the manifest declares "
            f"{manifest.bundle.version!r}."
        )
    _validate_manifest_structure(
        manifest,
        source=f"Downloaded bundle {entry.id!r}",
    )


def register(app: typer.Typer) -> None:
    """Attach the bundle command group to the root Typer app."""
    app.add_typer(bundle_app, name="bundle")

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Compare the two ids printed in the error: the first is the catalog entry, the second is the downloaded bundle.yml.
  2. If the artifact is correct, update the catalog entry id to exactly match bundle.yml.
  3. If the catalog id is correct, republish the artifact with the matching bundle id and update its URL if needed.
  4. Publish both catalog and manifest together in the same release change to prevent recurrence.

Example fix

# catalog.json (before)
{"id": "my-old-bundle", "download_url": "https://example.com/my-new-bundle.zip"}

# catalog.json (after)
{"id": "my-new-bundle", "download_url": "https://example.com/my-new-bundle.zip"}
Defensive patterns

Strategy: try-catch

Validate before calling

def catalog_and_manifest_ids_match(entry, manifest) -> bool:
    return manifest.bundle.id == entry.id

Try / catch

except BundlerError as exc:
    if "bundle id mismatch" in str(exc):
        block_install_and_alert_catalog_maintainer()
    else:
        raise

Prevention

When it happens

Trigger: `specify bundle info/install/update` downloads a manifest through `_download_manifest`, then `_validate_catalog_manifest` compares `manifest.bundle.id` with `entry.id` and finds a mismatch.

Common situations: A bundle was renamed but the catalog entry or artifact URL was not updated, a catalog entry was copied and its id was changed without changing the target manifest, or a release URL now points at a different artifact.

Related errors


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