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 whileView on GitHub (pinned to bf88c9f9a8)
Solutions
- 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.