{"record":{"id":"8e2d8d42963bd380","repo":"github/spec-kit","slug":"candidate-is-not-a-recognised-bundle-source","errorCode":null,"errorMessage":"'{candidate}' is not a recognised bundle source (.zip artifact, bundle directory, or bundle.yml).","messagePattern":"'(.+?)' is not a recognised bundle source \\(\\.zip artifact, bundle directory, or bundle\\.yml\\)\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/commands/bundle/__init__.py","lineNumber":820,"sourceCode":"                f\"Could not read bundle.yml inside '{candidate}': {exc}\"\n            ) from exc\n        try:\n            data = _yaml.safe_load(text)\n        except _yaml.YAMLError as exc:\n            # The sibling directory/bundle.yml branches reach YAML through\n            # load_yaml(), which turns a parse failure into a BundlerError. This\n            # branch parses inline, so without this it raises a raw YAMLError --\n            # neither a ValueError nor an OSError -- which escapes\n            # bundle_install()'s `except BundlerError` as a traceback.\n            raise BundlerError(\n                f\"Invalid YAML in bundle.yml inside '{candidate}': {exc}\"\n            ) from exc\n        return BundleManifest.from_dict(data)\n\n    if candidate.name == \"bundle.yml\" or candidate.suffix in (\".yml\", \".yaml\"):\n        return BundleManifest.from_file(candidate)\n\n    raise BundlerError(\n        f\"'{candidate}' is not a recognised bundle source (.zip artifact, bundle \"\n        \"directory, or bundle.yml).\"\n    )\n\n\ndef _resolve_manifest_path(path: Path | None) -> Path:\n    target = (path or Path.cwd()).resolve()\n    if target.is_dir():\n        target = target / \"bundle.yml\"\n    if not target.exists():\n        raise BundlerError(f\"No bundle.yml found at '{target}'.\")\n    return target\n\n\ndef _download_manifest(resolved, *, offline: bool):\n    \"\"\"Resolve a bundle's manifest from its catalog ``download_url``.\n\n    Catalog ``download_url``s are HTTPS-only (``http`` allowed for localhost),","sourceCodeStart":802,"sourceCodeEnd":838,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/commands/bundle/__init__.py#L802-L838","documentation":"_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.","triggerScenarios":"specify bundle install ./bundle.tar.gz, ./bundle.json, or any existing non-YAML, non-zip file.","commonSituations":"Bundles distributed as .tar.gz; a leftover .txt/.json file at the expected path; downloading the wrong artifact format.","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."],"exampleFix":"# before\nspecify bundle install ./my-bundle.tar.gz\n\n# after\ntar xzf my-bundle.tar.gz\nspecify bundle install ./my-bundle","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ncandidate = Path(arg).expanduser()\nrecognized = (\n    candidate.is_dir()\n    or candidate.suffix == \".zip\"\n    or candidate.name == \"bundle.yml\"\n    or candidate.suffix in (\".yml\", \".yaml\")\n)\nif candidate.exists() and not recognized:\n    raise SystemExit(f\"Unsupported bundle source type: {candidate.suffix or 'no-extension'}\")","typeGuard":"def is_recognized_source(path: Path) -> bool:\n    return (\n        path.is_dir()\n        or path.suffix == \".zip\"\n        or path.name == \"bundle.yml\"\n        or path.suffix in (\".yml\", \".yaml\")\n    )","tryCatchPattern":"try:\n    manifest = _local_manifest_source(arg)\nexcept BundlerError as exc:\n    if \"not a recognised bundle source\" in str(exc):\n        # unpack and pass the bundle directory / bundle.yml instead\n        ...","preventionTips":["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."],"tags":["bundler","path","format","filesystem"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}