github/spec-kit · error · ValidationError

Preserved extension config conflict for '{manifest.id}': The

Error message

Preserved extension config conflict for '{manifest.id}': The current config(s) ({names}) in {dest_dir} differ from their rescued backup in {rescue_staging_dir}. Both copies have been preserved. The config(s) ({names}) exist only in {dest_dir} with no counterpart in the rescued backup at {rescue_staging_dir}. Reconcile {dest_dir} and {rescue_staging_dir} to the desired final state, delete {rescue_staging_dir}, then reinstall.

What it means

Error "Preserved extension config conflict for '{manifest.id}': The current config(s) ({names}) in {dest_dir} differ from their rescued backup in {rescue_staging_dir}. Both copies have been preserved. The config(s) ({names}) exist only in {dest_dir} with no counterpart in the rescued backup at {rescue_staging_dir}. Reconcile {dest_dir} and {rescue_staging_dir} to the desired final state, delete {rescue_staging_dir}, then reinstall." thrown in github/spec-kit.

Source

Thrown at src/specify_cli/extensions/__init__.py:2350

                    names = ", ".join(sorted(both_diverged))
                    msg_parts.append(
                        f"The current config(s) ({names}) in {dest_dir} differ"
                        f" from their rescued backup in {rescue_staging_dir}."
                        " Both copies have been preserved."
                    )
                if live_only_conflict:
                    names = ", ".join(sorted(live_only_conflict))
                    msg_parts.append(
                        f"The config(s) ({names}) exist only in {dest_dir}"
                        f" with no counterpart in the rescued backup at"
                        f" {rescue_staging_dir}."
                    )
                msg_parts.append(
                    f"Reconcile {dest_dir} and {rescue_staging_dir} to the"
                    f" desired final state, delete {rescue_staging_dir},"
                    " then reinstall."
                )
                raise ValidationError(" ".join(msg_parts))
        elif (
            dest_dir.exists()
            and not self.registry.is_installed(manifest.id)
            and (
                self._has_keep_config_marker(dest_dir)
                or self._is_legacy_keep_config_leftover(dest_dir)
            )
        ):
            for cfg_file in (
                list(dest_dir.glob("*-config.yml"))
                + list(dest_dir.glob("*-config.local.yml"))
            ):
                if cfg_file.is_symlink():
                    # `remove --keep-config` preserves a symlinked config
                    # because Path.is_file() follows symlinks. Its bytes cannot
                    # be safely rescued (the target may live outside dest_dir),
                    # and the rmtree below would delete the link and silently
                    # discard the kept configuration. Reject the reinstall while

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Reconcile the current config with the rescued backup to the desired state, delete the rescue staging directory, then reinstall.

When it happens

Trigger: Thrown at src/specify_cli/extensions/__init__.py:2350 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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