{"record":{"id":"e79f8d14d1dcc155","repo":"github/spec-kit","slug":"extension-component-id-is-not-bundled-and-netw","errorCode":null,"errorMessage":"Extension '{component.id}' is not bundled and network access is disabled; re-run without --offline or install it first with 'specify extension add {component.id}'.","messagePattern":"Extension '(.+?)' is not bundled and network access is disabled; re-run without --offline or install it first with 'specify extension add (.+?)'\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/services/primitives.py","lineNumber":272,"sourceCode":"\n        bundled = _locate_bundled_extension(component.id)\n        if bundled is not None:\n            # Enforce the manifest pin against the bundled asset's own version,\n            # mirroring the catalog path below (the bundled path previously\n            # skipped the pin entirely).\n            _assert_pinned_version(\n                \"Extension\",\n                component.id,\n                component.version,\n                _bundled_manifest_version(bundled / \"extension.yml\", \"extension\"),\n            )\n            self._manager.install_from_directory(\n                bundled, speckit_version, priority=priority, force=force\n            )\n            return\n\n        if not self._allow_network:\n            raise BundlerError(\n                f\"Extension '{component.id}' is not bundled and network access is \"\n                f\"disabled; re-run without --offline or install it first with \"\n                f\"'specify extension add {component.id}'.\"\n            )\n\n        from ...extensions import ExtensionCatalog\n\n        catalog = ExtensionCatalog(self._root)\n        info = catalog.get_extension_info(component.id)\n        if not info:\n            raise BundlerError(\n                f\"Extension '{component.id}' not found in any catalog.\"\n            )\n        if not info.get(\"_install_allowed\", True):\n            raise BundlerError(\n                f\"Extension '{component.id}' is from a discovery-only catalog; \"\n                \"installation is not allowed.\"\n            )","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/services/primitives.py#L254-L290","documentation":"An extension component is not present in the bundle artifact's bundled/ tree, so installing it requires the network, but the bundler was run with allow_network=False (--offline). The message offers both remedies: re-run online or pre-install with `specify extension add <id>`.","triggerScenarios":"`specify bundle install <artifact> --offline` where the artifact does not vendor the extension directory, reaching the `if not self._allow_network` branch in _ExtensionKindManager.install at primitives.py:270.","commonSituations":"Air-gapped CI installs of bundles that pin catalog extensions without vendoring them; --offline used to make installs deterministic but the bundle expects remote fetch.","solutions":["Pre-install the extension online once: `specify extension add <id>`, then run the offline bundle install.","Drop --offline for this bundle if network is permitted.","Rebuild the bundle with the extension vendored into bundled/ for permanently offline targets."],"exampleFix":"specify extension add my-extension   # once, with network\nspecify bundle install my-bundle-1.0.0.zip --offline","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef offline_ready(artifact_dir: Path, component_id: str) -> bool:\n    bundled = artifact_dir / \"bundled\" / \"extensions\" / component_id\n    return bundled.is_dir() or extension_already_installed(project_root, component_id)","typeGuard":null,"tryCatchPattern":"from specify_cli.bundler.core import BundlerError\n\ntry:\n    install_bundle(project_root, plan, installer, allow_network=False)\nexcept BundlerError as exc:\n    if \"network access is disabled\" in str(exc):\n        subprocess.run([\"specify\", \"extension\", \"add\", extract_id(str(exc))], check=True)\n        install_bundle(project_root, plan, installer, allow_network=False)","preventionTips":["Pre-stage extensions with `specify extension add <id>` before offline bundle installs.","Build offline-targeted bundles with extensions vendored under bundled/.","Exercise the full offline install path in CI against a clean project."],"tags":["bundler","offline","extension","network"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}