BigPizzaV3/CodexPlusPlus · error · anyhow::Error
Dream Skin theme backup belongs to a different config.toml
Error message
Dream Skin theme backup belongs to a different config.toml
What it means
restore_base_theme reads the JSON backup and compares its stored config_path against the current config.toml path (textual comparison via to_string_lossy). A mismatch means the backup was captured against a different config.toml; restoring would corrupt this one, so it refuses. When no backup file exists, restore is a clean no-op.
Source
Thrown at crates/codex-plus-core/src/dream_skin.rs:300
}
if uses_native_chrome_theme(theme) {
restore_backup_setting(desktop, &backup, "appearanceLightCodeThemeId")?;
restore_backup_setting(desktop, &backup, "appearanceLightChromeTheme")?;
} else {
desktop["appearanceLightCodeThemeId"] = value("codex");
desktop["appearanceLightChromeTheme"] =
Item::Value(Value::InlineTable(target_chrome_theme(theme, profile)));
}
write_config(config_path, document.to_string().as_bytes())
}
fn restore_base_theme(config_path: &Path, backup_path: &Path) -> anyhow::Result<()> {
if !backup_path.exists() {
return Ok(());
}
let backup = read_backup(backup_path)?;
if backup.config_path != config_path.to_string_lossy() {
bail!("Dream Skin theme backup belongs to a different config.toml");
}
let existing = read_config_or_empty(config_path)?;
let mut document = parse_config(&existing, config_path)?;
if document.get("desktop").is_none() {
document["desktop"] = Item::Table(Table::new());
}
let desktop = desktop_table_mut(&mut document)?;
for key in APPEARANCE_KEYS {
match backup.values.get(key).and_then(Option::as_deref) {
Some(serialized) => {
desktop[key] = parse_backup_item(&backup, serialized)
.with_context(|| format!("failed to restore Dream Skin setting {key}"))?;
}
None => {
desktop.remove(key);
}
}View on GitHub (pinned to f2074595a2)
Solutions
- Restore while pointed at the same config.toml path that was active when the theme was applied
- If the old path is gone for good, delete the stale backup file - restore then no-ops cleanly
- Set CODEX_HOME consistently across apply and restore
Defensive patterns
Strategy: validation
Validate before calling
fn backup_targets_config(backup_path: &std::path::Path, config_path: &std::path::Path) -> bool {
std::fs::read(backup_path)
.ok()
.and_then(|b| serde_json::from_slice::<serde_json::Value>(&b).ok())
.and_then(|v| {
v.get("config_path")?
.as_str()
.map(|s| s == config_path.to_string_lossy())
})
.unwrap_or(false)
} Prevention
- Keep CODEX_HOME stable across apply and restore cycles
- Delete orphaned dream-skin backups when config.toml relocates
- The comparison is textual - symlinked homes that resolve differently will mismatch
When it happens
Trigger: CODEX_HOME changed, or config.toml was moved or renamed, between applying a theme and restoring it; a state dir reused with a different config path layout.
Common situations: Users relocating their codex home; machine migration; one state dir shared by several profiles.
Related errors
- unsupported Dream Skin backup schema
- invalid Dream Skin destination name
- Dream Skin image is not a file
- Dream Skin image is empty
- Dream Skin source image exceeds 50 MiB
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@f2074595a2 (2026-08-23).
Data as JSON: /api/errors/745adf5be2d4c221.
Report an issue: GitHub.