github/spec-kit · error · BundlerError
Failed to remove preset '{component.id}': {exc}
Error message
Failed to remove preset '{component.id}': {exc} What it means
During bundle removal, PresetManager.remove(component.id) raised an unexpected exception, which the bundler wraps as BundlerError with the original message preserved. The caller (remove_bundle) will then classify the removal state (see error 122) — this preset was the component that failed.
Source
Thrown at src/specify_cli/bundler/services/primitives.py:223
)
_assert_pinned_version(
"Preset", component.id, component.version, info.get("version")
)
zip_path = catalog.download_pack(component.id)
try:
self._manager.install_from_zip(
zip_path, speckit_version, priority, **({"force": True} if force else {})
)
finally:
with contextlib.suppress(Exception):
if zip_path.exists():
zip_path.unlink()
def remove(self, component: ComponentRef) -> None:
try:
self._manager.remove(component.id)
except Exception as exc: # noqa: BLE001
raise BundlerError(
f"Failed to remove preset '{component.id}': {exc}"
) from exc
class _ExtensionKindManager:
def __init__(self, project_root: Path, allow_network: bool) -> None:
from ...extensions import ExtensionManager
self._root = project_root
self._allow_network = allow_network
self._manager = ExtensionManager(project_root)
def is_installed(self, component: ComponentRef) -> bool:
try:
return self._manager.registry.is_installed(component.id)
except Exception: # noqa: BLE001
return False
View on GitHub (pinned to bf88c9f9a8)
Solutions
- Read the embedded {exc} to identify the concrete failure (missing path vs permission).
- If the preset is already gone, restore state consistency: reinstall the preset (`specify preset add <id>`) then remove the bundle, or clean up its record manually.
- Fix permissions on the preset directory and retry the bundle remove.
- Finish with `specify bundle list` to confirm the bundle record is gone.
Defensive patterns
Strategy: try-catch
Validate before calling
from specify_cli.presets import PresetManager
manager = PresetManager(project_root)
for c in bundle_preset_components:
if not manager.is_installed(c.id): # adjust to actual API
print(f"preset {c.id} missing; state may be out of sync") Try / catch
from specify_cli.bundler.core import BundlerError
try:
remove_bundle(project_root, bundle_id, installer)
except BundlerError as exc:
if "Failed to remove preset" in str(exc):
# exc.__cause__ holds PresetManager.remove's original exception
reconcile_preset_state(str(exc.__cause__)) Prevention
- Never delete preset directories by hand — uninstall via `specify preset remove` so records stay consistent.
- Before bundle remove, verify each contributed component still exists as the records expect.
- Fix the underlying {exc} (permissions/missing files) before retrying the bundle remove.
When it happens
Trigger: Uninstalling a bundle whose preset component's remove() throws — preset files already deleted by hand, .specify/presets state out of sync, or permission errors on the preset directory.
Common situations: User manually deleted a preset directory before running bundle remove; two tools managing the same preset; read-only filesystem mount.
Related errors
- Failed to remove bundle '{bundle_id}': {exc}. {detail}
- Failed to remove extension '{component.id}': {exc}
- '{target}' is a built-in default source and cannot be delete
- No project-scoped catalog source matching '{target}' was fou
- Failed to install bundle '{plan.bundle_id}': {exc}. No chang
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/117cdd0cc3dcbb42.
Report an issue: GitHub.