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
- Compare the two ids printed in the error: the first is the catalog entry, the second is the downloaded bundle.yml.
- If the artifact is correct, update the catalog entry id to exactly match bundle.yml.
- If the catalog id is correct, republish the artifact with the matching bundle id and update its URL if needed.
- 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
- Publish catalog.json and bundle.yml atomically in one release change.
- Run an automated post-publish check that downloads each catalog URL and compares ids.
- Never reuse an old entry id for a renamed bundle.
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
- Downloaded bundle version mismatch for {entry.id!r}: catalog
- Refusing to download {label}: URL is malformed: {url}
- Refusing to download {label} over non-HTTPS URL: {url}
- Refusing to download {label} from URL with no host: {url}
- Failed to download bundle '{entry_id}' from {_source_desc}:
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/2bf0fbd9defbe291.
Report an issue: GitHub.