github/spec-kit · error · PresetError
Failed to save preset archive: {e}
Error message
Failed to save preset archive: {e} What it means
The archive bytes downloaded but could not be persisted locally: an IOError/OSError (excluding URLError, caught earlier) occurred while writing the staging file or during the atomic os.replace into the cache. Raised as PresetError; the finally block unlinks the partial staging file so no corrupt archive remains.
Source
Thrown at src/specify_cli/presets/__init__.py:4959
)
archive_path = build_safe_download_path(
target_dir,
pack_id,
version,
error_type=PresetError,
label="preset",
suffix=archive_suffix(archive_format),
)
os.replace(staging_path, archive_path)
staging_path = None
return archive_path
except urllib.error.URLError as e:
raise PresetError(
f"Failed to download preset from {download_url}: {e}"
)
except IOError as e:
raise PresetError(f"Failed to save preset archive: {e}")
finally:
if staging_path is not None:
staging_path.unlink(missing_ok=True)
def clear_cache(self):
"""Clear all catalog cache files, including per-URL hashed caches."""
if self.cache_dir.exists():
for f in self.cache_dir.iterdir():
if f.is_file() and f.name.startswith("catalog"):
f.unlink(missing_ok=True)
class PresetResolver:
"""Resolves template names to file paths using a priority stack.
Resolution order:
1. .specify/templates/overrides/ - Project-local overrides
2. .specify/presets/<preset-id>/ - Installed presetsView on GitHub (pinned to bf88c9f9a8)
Solutions
- Check free disk space and expand/clean the cache partition
- Fix ownership/permissions of the preset cache directory (often ~/.cache/specify or the configured cache_dir)
- Pass a writable target_dir to download_preset_archive if the default cache path is restricted
- Remove stale root-owned archive files blocking os.replace
Example fix
# before archive = manager.download_preset_archive(pack_id) # default cache dir read-only # after archive = manager.download_preset_archive(pack_id, target_dir="/tmp/writable-downloads")
Defensive patterns
Strategy: try-catch
Validate before calling
import shutil target = pathlib.Path(target_dir or manager.cache_dir / "downloads") writable = target.exists() and os.access(target, os.W_OK) free_ok = shutil.disk_usage(target).free > 100 * 1024 * 1024 # 100MB headroom
Try / catch
try:
archive = manager.download_preset_archive(pack_id)
except PresetError as e:
if "Failed to save preset archive" in str(e):
archive = manager.download_preset_archive(pack_id, target_dir=tempfile.mkdtemp())
else:
raise Prevention
- Ensure the preset cache directory is writable by the running user before downloads
- Keep free disk space headroom sized to your largest preset archives
- Avoid mixing sudo/root runs that leave root-owned files in the cache dir
When it happens
Trigger: Cache/download directory is read-only or out of disk space; permissions missing on the cache dir; target path on a filesystem that fails the rename (cross-device or immutable file).
Common situations: Running with a restricted HOME or XDG cache; CI container with a small tmpfs filling up; cache dir owned by root after a previous sudo run; antivirus/locking interfering with os.replace on some platforms.
Related errors
- Preset '{pack_id}' is from the '{catalog_name}' catalog whic
- Could not read manifest {path}: {e}
- Invalid {singular} entry '{name}': 'strategy' is not authora
- Could not safely create download file: {exc}
- Invalid YAML in {path}: {e}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/cf21679691c7ee5f.
Report an issue: GitHub.