github/spec-kit · error · BundlerError
Downloaded artifact for bundle '{entry_id}' from {_source_de
Error message
Downloaded artifact for bundle '{entry_id}' from {_source_desc} is not a valid bundle: {exc} What it means
The downloaded bytes were identified as a ZIP archive, either because the catalog URL ends in .zip or the payload starts with a ZIP signature, but extracting its manifest failed. Spec Kit writes the payload to a temporary file and reuses the local bundle reader, which requires a readable archive containing a root-level bundle.yml.
Source
Thrown at src/specify_cli/commands/bundle/__init__.py:1026
# Detection uses the path component of the original catalog URL (via
# PurePosixPath so query strings and fragments are ignored, and URL paths
# are always treated as POSIX regardless of host OS), falling back to the
# module-level _ZIP_SIGNATURES magic-byte check for direct REST API asset
# URLs which carry no file extension.
_url_ext = PurePosixPath(_urlparse(url).path).suffix.lower()
try:
if _url_ext == ".zip" or raw[:4] in _ZIP_SIGNATURES:
with tempfile.TemporaryDirectory() as tmp:
artifact = Path(tmp) / "bundle.zip"
artifact.write_bytes(raw)
# Wrap ZIP parsing so any failure (BadZipFile, missing
# bundle.yml, etc.) references the source URL rather than the
# opaque temporary path, consistent with the download-error
# handling above.
try:
manifest = _local_manifest_source(str(artifact))
except Exception as exc: # noqa: BLE001
raise BundlerError(
f"Downloaded artifact for bundle '{entry_id}' from "
f"{_source_desc} is not a valid bundle: {exc}"
) from exc
# _local_manifest_source returns None only when the file does
# not exist; since we just wrote *artifact* that cannot happen
# here. The explicit guard ensures callers never receive None
# and silently degrade instead of raising a clear error.
if manifest is None:
raise BundlerError(
f"Downloaded artifact for bundle '{entry_id}' from "
f"{_source_desc} is not a valid bundle."
)
return manifest
data = _yaml.safe_load(io.BytesIO(raw))
return BundleManifest.from_dict(data)
except BundlerError:
raiseView on GitHub (pinned to bf88c9f9a8)
Solutions
- Download the exact URL from the error and run `unzip -l <file>` to inspect the archive.
- Ensure `bundle.yml` is at the archive root, not under `my-bundle/` or `dist/`.
- Rebuild and upload the complete ZIP artifact, then update the catalog if the URL changed.
- If the payload is actually YAML, remove the misleading `.zip` extension from the download URL.
- If the response is HTML, fix authentication or the direct-asset URL before republishing.
Example fix
# archive layout (before) my-bundle/ bundle.yml # archive layout (after) bundle.yml
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
from zipfile import ZipFile
def zip_is_valid_bundle_artifact(path: Path) -> bool:
try:
with ZipFile(path) as archive:
names = set(archive.namelist())
return "bundle.yml" in names and archive.testzip() is None
except Exception:
return False Try / catch
except BundlerError as exc:
if "is not a valid bundle" in str(exc):
inspect_remote_zip_layout()
else:
raise Prevention
- Add a CI check that every published bundle ZIP has root-level bundle.yml and passes zipfile.testzip().
- Build artifacts with `specify bundle build` rather than manually zipping the repository.
- Ensure direct asset URLs do not return HTML login pages.
When it happens
Trigger: The artifact is truncated or corrupt, bundle.yml is missing from the ZIP root, bundle.yml is nested under a directory, a ZIP member is oversized, or bundle.yml cannot be decoded/parsed. The underlying failure text is appended after the colon.
Common situations: A maintainer zipped the project directory instead of running the bundle build output, uploaded a tar.gz while naming the URL .zip, uploaded an incomplete file, or pointed a `.zip` URL at an HTML login/error page.
Related errors
- Downloaded content for bundle '{entry_id}' from {_source_des
- {source} contains an invalid bundle manifest:\n - " + "\n
- Manifest must be a YAML mapping at the top level.
- Manifest is missing the required 'bundle' mapping.
- 'requires' must be a mapping when present.
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/fad8bbd696036729.
Report an issue: GitHub.