Hmbown/CodeWhale · error · anyhow::Error
config changed after it was loaded; reload {} and retry inst
Error message
config changed after it was loaded; reload {} and retry instead of overwriting concurrent changes What it means
Config writes use optimistic concurrency: replace_config_document_if_unchanged() holds the write lock, re-reads the file, and requires it to still equal the snapshot the caller loaded. If the on-disk content differs from that expected snapshot (and is not already the desired body), the write is refused so concurrent edits are never overwritten; the caller must reload and retry.
Source
Thrown at crates/config/src/config_document.rs:101
/// acquired. This closes the `exists()`/create race in first-run writers.
pub fn create_config_document(path: &Path, body: &str) -> Result<()> {
replace_config_document_if_unchanged(path, None, body)
}
/// Replace a full typed snapshot only when on-disk bytes still equal the
/// snapshot the caller originally loaded. `None` means the file was absent.
pub fn replace_config_document_if_unchanged(
path: &Path,
expected: Option<&str>,
body: &str,
) -> Result<()> {
with_config_write_lock(path, |path| {
let current = read_optional_config(path)?;
if current.as_deref() == Some(body) {
return Ok(());
}
if current.as_deref() != expected {
bail!(
"config changed after it was loaded; reload {} and retry instead of overwriting concurrent changes",
crate::quote_os_path(path)
);
}
persist_locked(path, current.as_deref(), body.as_bytes())
})
}
/// Set a value at `segments`, creating implicit parent tables while preserving
/// existing key/value decor.
pub fn set_config_document_value(
doc: &mut toml_edit::DocumentMut,
segments: &[&str],
value: impl Into<toml_edit::Value>,
) -> Result<()> {
let (key, parents) = segments
.split_last()
.context("config value path must not be empty")?;View on GitHub (pinned to 0c42157ee5)
Solutions
- Reload config.toml and retry the same mutation — the standard recovery named in the message
- Close or pause the other Codewhale session that wrote config.toml before retrying
- Serialize your config edits (apply them from one process at a time) instead of racing concurrent writers
- If it recurs with a single process, check for external tools (sync agents, editors) rewriting the file underneath Codewhale
Example fix
// before (write once with a stale snapshot)
replace_config_document_if_unchanged(&path, Some(&loaded), &new_body)?; // bails if file changed
// after (reload and retry)
match replace_config_document_if_unchanged(&path, Some(&loaded), &new_body) {
Err(_) if config_changed_on_disk(&path) => {
let loaded = std::fs::read_to_string(&path)?; // reload
replace_config_document_if_unchanged(&path, Some(&loaded), &new_body)?;
}
other => other?,
} Defensive patterns
Strategy: retry
Validate before calling
// Compare the on-disk document with your snapshot immediately before writing:
let current = std::fs::read_to_string(&path).ok();
if current.as_deref() != Some(&loaded_snapshot) {
// someone else wrote in between: reload now instead of failing later
loaded_snapshot = current.unwrap_or_default();
// re-apply your edit to the fresh snapshot before calling replace
} Try / catch
// classic optimistic-lock retry loop:
for _ in 0..3 {
let snapshot = read_optional_config(&path)?;
let body = apply_edit(&snapshot, &edit)?;
match replace_config_document_if_unchanged(&path, snapshot.as_deref(), &body) {
Ok(()) => return Ok(()),
Err(e) if e.to_string().contains("config changed after it was loaded") => continue,
Err(e) => return Err(e),
}
}
bail!("config kept changing; retry later") Prevention
- Run one config-mutating Codewhale process at a time
- Reload-and-retry immediately on this error instead of overwriting
- Keep external editors/sync tools away from config.toml during sessions
When it happens
Trigger: Two Codewhale processes (e.g. a TUI session and a CLI command, or two agents) load config.toml, both modify it, and the second one calls replace_config_document_if_unchanged() after the first already persisted — current != expected triggers the bail.
Common situations: Long-lived TUI session open while a background agent or second terminal mutates settings; scripted config edits racing an interactive session; editors with auto-save touching config.toml between load and write.
Related errors
- parallel(): max 1000 items per call
- This browser session is not authenticated. Restart `codewhal
- max_chars must be > 0
- runtime API returned {status}
- Codewhale account API base URL must not contain a query or f
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/ddf1b42118beb8a1.
Report an issue: GitHub.