{"record":{"id":"3e8b9e9380fdad7a","repo":"github/spec-kit","slug":"no-bundle-yml-found-in-bundle-dir","errorCode":null,"errorMessage":"No bundle.yml found in '{bundle_dir}'.","messagePattern":"No bundle\\.yml found in '(.+?)'\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/services/packager.py","lineNumber":41,"sourceCode":"\n# Fixed member timestamp (zip epoch) for reproducible, byte-stable artifacts.\n_FIXED_TIMESTAMP = (1980, 1, 1, 0, 0, 0)\n\n\n@dataclass\nclass BuildResult:\n    artifact_path: Path\n    file_count: int\n\n\ndef build_bundle(\n    bundle_dir: Path,\n    output_dir: Path | None = None,\n) -> BuildResult:\n    bundle_dir = Path(bundle_dir).resolve()\n    manifest_path = bundle_dir / \"bundle.yml\"\n    if not manifest_path.exists():\n        raise BundlerError(f\"No bundle.yml found in '{bundle_dir}'.\")\n\n    # The artifact contract requires a human-facing README.md alongside the\n    # manifest; refuse early rather than publish a bundle with no description.\n    if not (bundle_dir / \"README.md\").exists():\n        raise BundlerError(\n            f\"No README.md found in '{bundle_dir}'. Every bundle must ship a \"\n            \"README.md describing it.\"\n        )\n\n    manifest = BundleManifest.from_file(manifest_path)\n    report = validate_manifest(manifest)\n    if not report.ok:\n        raise BundlerError(\n            \"Refusing to build an invalid manifest. Run 'specify bundle validate' \"\n            \"and fix:\\n  - \" + \"\\n  - \".join(report.errors)\n        )\n\n    out_dir = Path(output_dir).resolve() if output_dir else bundle_dir","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/services/packager.py#L23-L59","documentation":"build_bundle() requires the bundle source directory to contain a bundle.yml manifest; the check `(bundle_dir / \"bundle.yml\").exists()` failed. This fails fast before any validation or zip creation, so no artifact is produced.","triggerScenarios":"Calling build_bundle(bundle_dir) or `specify bundle build <dir>` on a directory that lacks bundle.yml — wrong directory passed, manifest named differently (bundle.yaml, manifest.yml), or the bundle scaffolding step was skipped.","commonSituations":"Passing the parent of the actual bundle folder; misnamed manifest file; starting a new bundle by hand and forgetting the manifest; running the build from the wrong cwd with a relative path.","solutions":["Confirm the directory actually contains the manifest: `ls <bundle_dir>/bundle.yml`.","If the file is named bundle.yaml or manifest.yml, rename it to bundle.yml.","Point the build at the directory that directly contains bundle.yml, not a parent or sibling directory.","If creating a new bundle, scaffold bundle.yml first (id, version, components) before building."],"exampleFix":"// before\nbuild_bundle(Path(\"bundles\"))  # bundles/ contains my-bundle/bundle.yml\n\n// after\nbuild_bundle(Path(\"bundles/my-bundle\"))","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef buildable(bundle_dir: Path) -> bool:\n    return (bundle_dir / \"bundle.yml\").is_file() and (bundle_dir / \"README.md\").is_file()","typeGuard":null,"tryCatchPattern":"from specify_cli.bundler.core import BundlerError\n\ntry:\n    result = build_bundle(bundle_dir)\nexcept BundlerError as exc:\n    print(f\"build failed: {exc}\"); raise","preventionTips":["Check for bundle.yml (and README.md) at the top of the bundle directory before invoking build.","Use absolute paths to the directory that directly contains bundle.yml.","Scaffold new bundles from a template that already includes both files."],"tags":["bundler","build","manifest","missing-file"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}