{"record":{"id":"c5e19bf43a62f79e","repo":"github/spec-kit","slug":"workflow-component-id-installs-from-a-catalog","errorCode":null,"errorMessage":"Workflow '{component.id}' installs from a catalog and network access is disabled; re-run without --offline or install it first with 'specify workflow add {component.id}'.","messagePattern":"Workflow '(.+?)' installs from a catalog and network access is disabled; re-run without --offline or install it first with 'specify workflow add (.+?)'\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/services/primitives.py","lineNumber":329,"sourceCode":"\n\nclass _WorkflowKindManager:\n    def __init__(self, project_root: Path, allow_network: bool) -> None:\n        from ...workflows.catalog import WorkflowRegistry\n\n        self._root = project_root\n        self._allow_network = allow_network\n        self._registry = WorkflowRegistry(project_root)\n\n    def is_installed(self, component: ComponentRef) -> bool:\n        try:\n            return self._registry.is_installed(component.id)\n        except Exception:  # noqa: BLE001\n            return False\n\n    def install(self, component: ComponentRef) -> None:\n        if not self._allow_network and not self._is_bundled(component.id):\n            raise BundlerError(\n                f\"Workflow '{component.id}' installs from a catalog and network \"\n                f\"access is disabled; re-run without --offline or install it first \"\n                f\"with 'specify workflow add {component.id}'.\"\n            )\n        self._assert_pinned_version(component)\n        from ... import workflow_add\n\n        with _chdir(self._root):\n            _delegate_command(\n                \"install\", f\"workflow '{component.id}'\",\n                lambda: workflow_add(component.id),\n            )\n\n    def refresh(self, component: ComponentRef) -> None:\n        # workflow_add is idempotent for already-installed workflows; delegate\n        # to the standard install path which handles version refresh correctly.\n        self.install(component)\n","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/services/primitives.py#L311-L347","documentation":"Workflow components are installed by delegating to `specify workflow add`, which fetches from a catalog. If the workflow is not vendored in the artifact's bundled/ tree (checked via _is_bundled) and the bundler runs with --offline, installation is refused up front, before any delegation or version assertion.","triggerScenarios":"`specify bundle install <artifact> --offline` where the manifest includes a workflows component and the artifact does not contain the workflow locally: `not allow_network and not self._is_bundled(id)` is True at primitives.py:336.","commonSituations":"Offline/air-gapped CI with bundles that only pin catalog workflows; --offline chosen for determinism but the bundle expects remote fetch.","solutions":["Pre-install the workflow online once: `specify workflow add <id>`, then re-run the offline bundle install.","Re-run the bundle install without --offline.","Rebuild the bundle with the workflow vendored under bundled/ so no network is needed."],"exampleFix":"specify workflow add my-workflow   # 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, workflow_id: str) -> bool:\n    bundled = artifact_dir / \"bundled\" / \"workflows\" / workflow_id\n    return bundled.is_dir() or workflow_already_installed(project_root, workflow_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\", \"workflow\", \"add\", extract_id(str(exc))], check=True)\n        install_bundle(project_root, plan, installer, allow_network=False)","preventionTips":["Pre-install workflows with `specify workflow add <id>` before offline installs.","Vendor workflows into the bundle's bundled/ tree for offline targets.","Remember workflows differ from steps: workflows can be vendored, steps (currently) cannot."],"tags":["bundler","offline","workflow","network"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}