{"record":{"id":"40a1f266d4b2c2eb","repo":"github/spec-kit","slug":"failed-to-remove-bundle-bundle-id-exc-det","errorCode":null,"errorMessage":"Failed to remove bundle '{bundle_id}': {exc}. {detail}","messagePattern":"Failed to remove bundle '(.+?)': (.+?)\\. (.+?)","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/services/installer.py","lineNumber":224,"sourceCode":"    except Exception as exc:  # noqa: BLE001\n        if result.uninstalled:\n            detail = (\n                f\"{len(result.uninstalled)} component(s) were already removed \"\n                \"before this failure; the bundle record was left unchanged, \"\n                \"so the project may be partially uninstalled.\"\n            )\n        elif remove_attempted:\n            detail = (\n                \"No components were removed, but the failing component may \"\n                \"have made partial changes before raising, so the project \"\n                \"may be partially uninstalled.\"\n            )\n        else:\n            detail = (\n                \"No components were removed and no removal was attempted; \"\n                \"the bundle record was left unchanged.\"\n            )\n        raise BundlerError(\n            f\"Failed to remove bundle '{bundle_id}': {exc}. {detail}\"\n        ) from exc\n\n    return result\n\n\ndef _refresh_component(\n    project_root: Path,\n    installer: PrimitiveInstaller,\n    component: ComponentRef,\n) -> None:\n    \"\"\"Re-apply an already-installed component to bring it up to its pinned version.\n\n    Prefers a primitive-provided ``refresh`` hook when available; otherwise falls\n    back to a re-install through the existing idempotent install path.\n    \"\"\"\n    op = getattr(installer, \"refresh\", None)\n    if callable(op):","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/services/installer.py#L206-L242","documentation":"An unexpected exception occurred while uninstalling a bundle. The message distinguishes how far the removal got: either some components were already removed, a removal was attempted but nothing completed (partial uninstall possible), or nothing was attempted at all (record left unchanged). This tells you whether your project may be in a partially uninstalled state.","triggerScenarios":"Calling remove_bundle() where installer.remove() raises for one of target.contributed_components — e.g. a preset/extension manager remove() failing on a missing or locked file. If an earlier component already succeeded, result.removed is non-empty; if the first remove fails, remove_attempted is True with empty removed; if the failure happened before the loop, neither is set.","commonSituations":"Uninstalling a bundle while one of its extensions/presets has files locked or already deleted by hand; permission errors under .specify or the agent config dirs; a component directory that was manually moved or renamed.","solutions":["Parse the {detail} clause: 'partially uninstalled' means you must inspect and finish cleanup by hand; 'record was left unchanged' means a plain retry is safe.","Fix the underlying cause named in {exc} (permissions, missing file, locked file) and re-run `specify bundle remove`.","After a partial uninstall, remove the leftover components individually (`specify preset remove <id>`, `specify extension remove <id>`) and then re-run the bundle remove to clear the record.","Verify final state with `specify bundle list` and by checking the component directories."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"from specify_cli.bundler.services.installer import load_records\nfrom pathlib import Path\n\nrecords = load_records(project_root)\ntarget = next((r for r in records if r.bundle_id == bundle_id), None)\nif target is None:\n    return\nfor c in target.contributed_components:\n    # surface likely failures before the loop mutates anything\n    assert installer.is_installed(project_root, c), f\"{c.kind}/{c.id} missing\"","typeGuard":null,"tryCatchPattern":"from specify_cli.bundler.core import BundlerError\n\ntry:\n    result = remove_bundle(project_root, bundle_id, installer)\nexcept BundlerError as exc:\n    msg = str(exc)\n    if \"partially uninstalled\" in msg:\n        enter_manual_cleanup_mode()   # inspect and finish removal by hand\n    elif \"record was left unchanged\" in msg:\n        fix_root_cause_and_retry()    # safe to retry after the cause is fixed","preventionTips":["Never hand-delete preset/extension directories; always remove via the CLI so bundle records stay in sync.","Branch on the {detail} clause — 'partially uninstalled' requires manual inspection.","After any failed remove, verify with `specify bundle list` before retrying."],"tags":["bundler","remove","partial-state","wrapper-error"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}