github/spec-kit · error · PresetError

Preset '{manifest.id}' is already installed. Use 'specify pr

Error message

Preset '{manifest.id}' is already installed. Use 'specify preset remove {manifest.id}' first.

What it means

install_from_directory refuses to install a preset whose manifest id is already present in the registry, unless force=True. This prevents silently overwriting an installed preset; the message points at the removal command. With force=True the manager instead removes the existing installation and continues.

Source

Thrown at src/specify_cli/presets/__init__.py:3567

        Returns:
            Installed preset manifest

        Raises:
            PresetValidationError: If manifest is invalid or priority is invalid
            PresetCompatibilityError: If pack is incompatible
        """
        # Validate priority
        if priority < 1:
            raise PresetValidationError("Priority must be a positive integer (1 or higher)")

        manifest_path = source_dir / "preset.yml"
        manifest = PresetManifest(manifest_path)

        self.check_compatibility(manifest, speckit_version)

        if self.registry.is_installed(manifest.id):
            if not force:
                raise PresetError(
                    f"Preset '{manifest.id}' is already installed. "
                    f"Use 'specify preset remove {manifest.id}' first."
                )
            self.remove(manifest.id)

        dest_dir = self.presets_dir / manifest.id
        if dest_dir.exists():
            shutil.rmtree(dest_dir)

        shutil.copytree(source_dir, dest_dir)

        # Pre-register the preset so that composition resolution can see it
        # in the priority stack when resolving composed command content.
        self.registry.add(manifest.id, {
            "version": manifest.version,
            "source": "local",
            "manifest_hash": manifest.get_hash(),
            "enabled": True,

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Remove first: `specify preset remove <id>` (as the message says), then reinstall.
  2. Or pass force=True to the programmatic call for idempotent installs.
  3. If the preset should not be registered, check for leftover registry entries from a failed install and clean them.

Example fix

# before
manager.install_from_directory(src, ver)

# after
manager.install_from_directory(src, ver, force=True)
Defensive patterns

Strategy: fallback

Validate before calling

if manager.registry.is_installed(pack_id):
    manager.remove(pack_id)  # or choose to skip
manager.install_from_directory(source_dir, speckit_version, priority=priority)

Try / catch

try:
    manager.install_from_directory(src, ver)
except PresetError as e:
    if "already installed" in str(e):
        manager.install_from_directory(src, ver, force=True)

Prevention

When it happens

Trigger: Running a second `specify preset add <same-id>` (or calling install_from_directory without force=True) while the preset id exists in .specify/presets/registry.json — including when the previous install partially failed but registered the id.

Common situations: Re-running an install script/idempotent CI step, iterating on a local preset during development, or reinstalling after a failed first attempt that had already pre-registered the entry.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/668877fefb4f2734. Report an issue: GitHub.