{"record":{"id":"55dd11f760e89105","repo":"github/spec-kit","slug":"source-path-is-the-install-destination-for-manif","errorCode":null,"errorMessage":"Source path is the install destination for '{manifest.id}' ({dest_dir}). Refusing to proceed to avoid deleting the extension. Install from a copy in a different location instead.","messagePattern":"Source path is the install destination for '(.+?)' \\((.+?)\\)\\. Refusing to proceed to avoid deleting the extension\\. Install from a copy in a different location instead\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/extensions/__init__.py","lineNumber":2108,"sourceCode":"                    f\"Extension '{manifest.id}' is already installed. \"\n                    f\"Use 'specify extension remove {manifest.id}' first, \"\n                    f\"or retry with --force to overwrite.\"\n                )\n\n        # Reject manifests that would shadow core commands or installed extensions.\n        self._validate_install_conflicts(manifest)\n\n        # Refuse to install an extension from its own install destination — with\n        # --force this would delete the source before copying it (issue #2990).\n        dest_dir = self.extensions_dir / manifest.id\n        try:\n            same_location = source_dir.resolve(strict=False) == dest_dir.resolve(\n                strict=False\n            )\n        except (OSError, RuntimeError):\n            same_location = source_dir.absolute() == dest_dir.absolute()\n        if same_location:\n            raise ValidationError(\n                f\"Source path is the install destination for '{manifest.id}' \"\n                f\"({dest_dir}). Refusing to proceed to avoid deleting the \"\n                f\"extension. Install from a copy in a different location instead.\"\n            )\n\n        # Remove existing installation AFTER all validations pass so that a\n        # validation failure doesn't leave the user with a half-uninstalled\n        # extension (configs stranded in .backup/).\n        did_remove = False\n        if force and self.registry.is_installed(manifest.id):\n            # Clear any stale backup from a previous remove so that only the\n            # backup produced by the current remove() call is restored later.\n            backup_config_dir = self.extensions_dir / \".backup\" / manifest.id\n            # Check is_symlink first: is_dir() follows symlinks so a\n            # symlink-to-directory would pass, but rmtree() raises on them.\n            if backup_config_dir.is_symlink():\n                backup_config_dir.unlink()\n            elif backup_config_dir.is_dir():","sourceCodeStart":2090,"sourceCodeEnd":2126,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/extensions/__init__.py#L2090-L2126","documentation":"Error \"Source path is the install destination for '{manifest.id}' ({dest_dir}). Refusing to proceed to avoid deleting the extension. Install from a copy in a different location instead.\" thrown in github/spec-kit.","triggerScenarios":"Thrown at src/specify_cli/extensions/__init__.py:2108 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Copy the extension source to a different directory and install from there so the destination is not the source."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}