{"record":{"id":"9ce4002aee4da8a1","repo":"github/spec-kit","slug":"failed-to-remove-extension-component-id-exc","errorCode":null,"errorMessage":"Failed to remove extension '{component.id}': {exc}","messagePattern":"Failed to remove extension '(.+?)': (.+?)","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/services/primitives.py","lineNumber":308,"sourceCode":"            )\n        _assert_pinned_version(\n            \"Extension\", component.id, component.version, info.get(\"version\")\n        )\n        zip_path = catalog.download_extension(component.id)\n        try:\n            self._manager.install_from_zip(\n                zip_path, speckit_version, priority=priority, force=force\n            )\n        finally:\n            with contextlib.suppress(Exception):\n                if zip_path.exists():\n                    zip_path.unlink()\n\n    def remove(self, component: ComponentRef) -> None:\n        try:\n            self._manager.remove(component.id)\n        except Exception as exc:  # noqa: BLE001\n            raise BundlerError(\n                f\"Failed to remove extension '{component.id}': {exc}\"\n            ) from exc\n\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","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/services/primitives.py#L290-L326","documentation":"During bundle removal, ExtensionManager.remove(component.id) raised an unexpected exception; the bundler wraps it as BundlerError, keeping the original message. remove_bundle's outer handler will report the partial-state detail (see error 122).","triggerScenarios":"Uninstalling a bundle whose extension component fails to remove — extension files already deleted by hand, stale .specify/extensions state, or filesystem permission errors.","commonSituations":"Manual deletion of an extension directory before bundle remove; extension uninstalled individually first, leaving the bundle record stale; locked files on Windows or read-only mounts.","solutions":["Inspect the embedded {exc} for the concrete cause (missing path, permission).","Re-sync state: reinstall the extension (`specify extension add <id>`) and then re-run the bundle remove, or remove it directly with `specify extension remove <id>`.","Fix filesystem permissions and retry.","Confirm cleanup with `specify bundle list` afterwards."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"from specify_cli.extensions import ExtensionManager\n\nmanager = ExtensionManager(project_root)\nfor c in bundle_extension_components:\n    if not manager.is_installed(c.id):  # adjust to actual API\n        print(f\"extension {c.id} missing; state may be out of sync\")","typeGuard":null,"tryCatchPattern":"from specify_cli.bundler.core import BundlerError\n\ntry:\n    remove_bundle(project_root, bundle_id, installer)\nexcept BundlerError as exc:\n    if \"Failed to remove extension\" in str(exc):\n        reconcile_extension_state(str(exc.__cause__))","preventionTips":["Remove extensions only via `specify extension remove`, never by deleting directories.","Verify extension state matches bundle records before removal.","Fix permissions/missing-file causes named in {exc} before retrying."],"tags":["bundler","extension","remove","wrapper-error"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}