{"record":{"id":"fad8bbd696036729","repo":"github/spec-kit","slug":"downloaded-artifact-for-bundle-entry-id-from","errorCode":null,"errorMessage":"Downloaded artifact for bundle '{entry_id}' from {_source_desc} is not a valid bundle: {exc}","messagePattern":"Downloaded artifact for bundle '(.+?)' from (.+?) is not a valid bundle: (.+?)","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/commands/bundle/__init__.py","lineNumber":1026,"sourceCode":"    # Detection uses the path component of the original catalog URL (via\n    # PurePosixPath so query strings and fragments are ignored, and URL paths\n    # are always treated as POSIX regardless of host OS), falling back to the\n    # module-level _ZIP_SIGNATURES magic-byte check for direct REST API asset\n    # URLs which carry no file extension.\n    _url_ext = PurePosixPath(_urlparse(url).path).suffix.lower()\n    try:\n        if _url_ext == \".zip\" or raw[:4] in _ZIP_SIGNATURES:\n            with tempfile.TemporaryDirectory() as tmp:\n                artifact = Path(tmp) / \"bundle.zip\"\n                artifact.write_bytes(raw)\n                # Wrap ZIP parsing so any failure (BadZipFile, missing\n                # bundle.yml, etc.) references the source URL rather than the\n                # opaque temporary path, consistent with the download-error\n                # handling above.\n                try:\n                    manifest = _local_manifest_source(str(artifact))\n                except Exception as exc:  # noqa: BLE001\n                    raise BundlerError(\n                        f\"Downloaded artifact for bundle '{entry_id}' from \"\n                        f\"{_source_desc} is not a valid bundle: {exc}\"\n                    ) from exc\n                # _local_manifest_source returns None only when the file does\n                # not exist; since we just wrote *artifact* that cannot happen\n                # here.  The explicit guard ensures callers never receive None\n                # and silently degrade instead of raising a clear error.\n                if manifest is None:\n                    raise BundlerError(\n                        f\"Downloaded artifact for bundle '{entry_id}' from \"\n                        f\"{_source_desc} is not a valid bundle.\"\n                    )\n                return manifest\n\n        data = _yaml.safe_load(io.BytesIO(raw))\n        return BundleManifest.from_dict(data)\n    except BundlerError:\n        raise","sourceCodeStart":1008,"sourceCodeEnd":1044,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/commands/bundle/__init__.py#L1008-L1044","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# archive layout (before)\nmy-bundle/\n  bundle.yml\n\n# archive layout (after)\nbundle.yml","handlingStrategy":"validation","validationCode":"from pathlib import Path\nfrom zipfile import ZipFile\n\ndef zip_is_valid_bundle_artifact(path: Path) -> bool:\n    try:\n        with ZipFile(path) as archive:\n            names = set(archive.namelist())\n            return \"bundle.yml\" in names and archive.testzip() is None\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"except BundlerError as exc:\n    if \"is not a valid bundle\" in str(exc):\n        inspect_remote_zip_layout()\n    else:\n        raise","preventionTips":["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."],"tags":["zip","bundle","manifest","download","validation"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}