github/spec-kit · error · BundlerError
'{candidate}' is not a recognised bundle source (.zip artifa
Error message
'{candidate}' is not a recognised bundle source (.zip artifact, bundle directory, or bundle.yml). What it means
_local_manifest_source dispatches on the argument's shape: .zip file, existing directory, or a file named bundle.yml / with .yml/.yaml suffix. The path existed but matched none of these (not a directory, not .zip, not a YAML file), so it is rejected as an unrecognised bundle source. Raising (instead of returning None) prevents the argument from falling through to catalog-by-id resolution, which would silently do the wrong thing.
Source
Thrown at src/specify_cli/commands/bundle/__init__.py:820
f"Could not read bundle.yml inside '{candidate}': {exc}"
) from exc
try:
data = _yaml.safe_load(text)
except _yaml.YAMLError as exc:
# The sibling directory/bundle.yml branches reach YAML through
# load_yaml(), which turns a parse failure into a BundlerError. This
# branch parses inline, so without this it raises a raw YAMLError --
# neither a ValueError nor an OSError -- which escapes
# bundle_install()'s `except BundlerError` as a traceback.
raise BundlerError(
f"Invalid YAML in bundle.yml inside '{candidate}': {exc}"
) from exc
return BundleManifest.from_dict(data)
if candidate.name == "bundle.yml" or candidate.suffix in (".yml", ".yaml"):
return BundleManifest.from_file(candidate)
raise BundlerError(
f"'{candidate}' is not a recognised bundle source (.zip artifact, bundle "
"directory, or bundle.yml)."
)
def _resolve_manifest_path(path: Path | None) -> Path:
target = (path or Path.cwd()).resolve()
if target.is_dir():
target = target / "bundle.yml"
if not target.exists():
raise BundlerError(f"No bundle.yml found at '{target}'.")
return target
def _download_manifest(resolved, *, offline: bool):
"""Resolve a bundle's manifest from its catalog ``download_url``.
Catalog ``download_url``s are HTTPS-only (``http`` allowed for localhost),View on GitHub (pinned to bf88c9f9a8)
Solutions
- Unpack the archive and pass the bundle directory or bundle.yml path instead.
- If you meant a catalog id, remove the path-looking argument (a non-existent path returns None and falls back to catalog resolution).
- Produce a .zip artifact or a directory with bundle.yml as the installable formats.
Example fix
# before specify bundle install ./my-bundle.tar.gz # after tar xzf my-bundle.tar.gz specify bundle install ./my-bundle
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
candidate = Path(arg).expanduser()
recognized = (
candidate.is_dir()
or candidate.suffix == ".zip"
or candidate.name == "bundle.yml"
or candidate.suffix in (".yml", ".yaml")
)
if candidate.exists() and not recognized:
raise SystemExit(f"Unsupported bundle source type: {candidate.suffix or 'no-extension'}") Type guard
def is_recognized_source(path: Path) -> bool:
return (
path.is_dir()
or path.suffix == ".zip"
or path.name == "bundle.yml"
or path.suffix in (".yml", ".yaml")
) Try / catch
try:
manifest = _local_manifest_source(arg)
except BundlerError as exc:
if "not a recognised bundle source" in str(exc):
# unpack and pass the bundle directory / bundle.yml instead
... Prevention
- Distribute bundles as a directory, bundle.yml, or .zip — not tarballs.
- Remember: a non-existent path falls back to catalog id resolution; an existing wrong-type path raises.
When it happens
Trigger: specify bundle install ./bundle.tar.gz, ./bundle.json, or any existing non-YAML, non-zip file.
Common situations: Bundles distributed as .tar.gz; a leftover .txt/.json file at the expected path; downloading the wrong artifact format.
Related errors
- No bundle.yml found in '{bundle_dir}'.
- No bundle.yml found in '{candidate}'.
- No bundle.yml found at '{target}'.
- Directory not found: {source_path}
- specify event ${{command}} (${{event}}) failed: ${{(e as Err
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/8e2d8d42963bd380.
Report an issue: GitHub.