github/spec-kit · error · ValidationError
Preserved extension config for '{manifest.id}' is a symlink
Error message
Preserved extension config for '{manifest.id}' is a symlink ({cfg_file.name}) in {dest_dir}, which cannot be safely rescued during reinstall. Resolve manually — replace the symlink with a regular file or remove it — then reinstall. What it means
Error "Preserved extension config for '{manifest.id}' is a symlink ({cfg_file.name}) in {dest_dir}, which cannot be safely rescued during reinstall. Resolve manually — replace the symlink with a regular file or remove it — then reinstall." thrown in github/spec-kit.
Source
Thrown at src/specify_cli/extensions/__init__.py:2371
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
# dest_dir is untouched so the user resolves it rather than
# losing the linked config.
raise ValidationError(
"Preserved extension config for "
f"'{manifest.id}' is a symlink ({cfg_file.name}) in "
f"{dest_dir}, which cannot be safely rescued during "
"reinstall. Resolve manually — replace the symlink with "
"a regular file or remove it — then reinstall."
)
if cfg_file.is_file():
# A kept config that cannot be read or stat'ed must not
# crash the reinstall with a raw OSError — and must not
# reach the rmtree below unrescued. Like the symlink
# guard above, reject while dest_dir is untouched so the
# preserved bytes are never lost.
try:
stranded_configs[cfg_file.name] = (
cfg_file.read_bytes(),
cfg_file.stat().st_mode,
)
except OSError as exc:View on GitHub (pinned to bf88c9f9a8)
Solutions
- Replace the symlinked config file with a regular file (or remove it), then reinstall the extension.
When it happens
Trigger: Thrown at src/specify_cli/extensions/__init__.py:2371 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/4292bd061c848cd8.
Report an issue: GitHub.