BigPizzaV3/CodexPlusPlus · error
failed to allocate a stale Dream Skin backup path
Error message
failed to allocate a stale Dream Skin backup path
What it means
isolate_stale_backup moves an orphaned Dream Skin base-theme backup (dream-skin-base-theme-backup.json) out of the way by renaming it to a timestamped *.stale-*.json path. It tries the plain timestamped name and up to 100 numbered variants; if all 100 candidate names already exist on disk, it gives up with this bail. It is a defensive exhaustion error — effectively 'cannot find a free filename for the stale backup after 100 attempts'.
Solutions
- List and delete (or archive) old dream-skin-base-theme-backup.stale-*.json files in the codex config directory to free up candidate names.
- Re-run the apply/restore operation — a new millisecond timestamp changes the candidate names, so this is almost always transient.
- Check the directory is writable and not a weird mount; verify with a manual rename of the stale backup file.
- If it recurs, manually move the original dream-skin-base-theme-backup.json aside yourself, then retry.
Example fix
// before (all 100 candidate names taken)
bail!("failed to allocate a stale Dream Skin backup path")
// after (user-side recovery)
// rm ~/.codex/dream-skin-base-theme-backup.stale-*.json && retry apply_base_theme Defensive patterns
Strategy: try-catch
Validate before calling
let stale_count = std::fs::read_dir(config_dir)?
.filter_map(|e| e.ok())
.filter(|e| e.file_name().to_string_lossy().starts_with("dream-skin-base-theme-backup.stale-"))
.count();
if stale_count > 90 { /* clean up stale backups before applying */ } Try / catch
match apply_base_theme(...) {
Err(e) if e.to_string().contains("failed to allocate a stale Dream Skin backup path") => {
// purge dream-skin-base-theme-backup.stale-*.json, then retry once
}
other => other?,
} Prevention
- Periodically purge old dream-skin-base-theme-backup.stale-*.json files from the codex config directory.
- Investigate root causes of repeated apply/restore failures that leave stale backups behind.
- Avoid tight loops that call apply_base_theme many times per millisecond.
When it happens
Trigger: Called from apply_base_theme or restore_base_theme when the existing backup file's identity is BackupIdentity::Stale (a leftover backup pointing at a different, now-nonexistent config path). The bail fires only when all 100 candidate names dream-skin-base-theme-backup.stale-{timestamp}{,-1..-99}.json already exist in the same directory.
Common situations: An extremely fast loop re-applying themes many times within the same millisecond timestamp while leftover stale backups accumulate; a directory flooded with thousands of stale backup files from repeated crashed/failed applies; a filesystem where exists() misreports (e.g. permission-restricted directory or unusual mounts) so every candidate appears to exist.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- restore conflict: file already exists
- 工作目录不存在:
- archived lookup task failed
- built-in Dream Skin theme cannot be deleted
- built-in Dream Skin theme is read-only
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/dfd6c1148c68504e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/dream_skin.rs:627
String::new()
} else {
format!("-{attempt}")
};
let isolated = backup_path.with_file_name(format!(
"dream-skin-base-theme-backup.stale-{timestamp}{suffix}.json"
));
if isolated.exists() {
continue;
}
std::fs::rename(backup_path, &isolated).with_context(|| {
format!(
"failed to isolate stale Dream Skin backup {}",
backup_path.display()
)
})?;
return Ok(isolated);
}
bail!("failed to allocate a stale Dream Skin backup path")
}
fn read_config_or_empty(path: &Path) -> anyhow::Result<String> {
match std::fs::read_to_string(path) {
Ok(contents) => Ok(contents),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(String::new()),
Err(error) => Err(error).with_context(|| format!("failed to read {}", path.display())),
}
}
fn parse_config(contents: &str, path: &Path) -> anyhow::Result<DocumentMut> {
contents
.parse::<DocumentMut>()
.with_context(|| format!("failed to parse {}", path.display()))
}
fn write_config(path: &Path, bytes: &[u8]) -> anyhow::Result<()> {
crate::settings::atomic_write(path, bytes).with_context(|| {View on GitHub (pinned to b1ed92e5e4)