zeroclaw-labs/zeroclaw · error · anyhow::Error
config at {} is schema_version {from}; run `zeroclaw config
Error message
config at {} is schema_version {from}; run `zeroclaw config migrate` to update before modifying What it means
ensure_disk_at_current_version also refuses configs older than V3, but unlike the newer-than-binary case this one is recoverable in place: it directs you to run `zeroclaw config migrate`. Modifying APIs are gated on this check so stale-format files are never partially edited by code that assumes the current layout.
Source
Thrown at crates/zeroclaw-config/src/migration.rs:753
return Err(anyhow::Error::from(e)).with_context(|| {
format!("failed to read config at {}", path.display().to_string())
});
}
};
let value: toml::Value =
toml::from_str(&raw).context("failed to parse config TOML for version check")?;
let from = detect_version(&value)?;
if from == CURRENT_SCHEMA_VERSION {
return Ok(());
}
if from > CURRENT_SCHEMA_VERSION {
anyhow::bail!(
"config at {} is schema_version {from}, newer than this binary supports ({})",
path.display().to_string(),
CURRENT_SCHEMA_VERSION,
);
}
anyhow::bail!(
"config at {} is schema_version {from}; run `zeroclaw config migrate` to update before modifying",
path.display().to_string(),
);
}
pub(crate) fn fold_string_into_array(
table: &mut toml::Table,
from_key: &str,
to_key: &str,
) -> bool {
let value = match table.remove(from_key) {
Some(toml::Value::String(s)) if !s.is_empty() => s,
Some(other) => {
// Non-string: re-insert under from_key untouched (caller may handle).
table.insert(from_key.to_string(), other);
return false;
}
None => return false,View on GitHub (pinned to 88bb9c8533)
Solutions
- Run `zeroclaw config migrate` and let it walk the migration chain forward to V3.
- Verify the file afterwards: schema_version = 3 at the top of the TOML, then retry the original operation.
- Keep a backup before migrating (the chain is forward-only) in case a hand-edited field cannot be transformed.
- If migration fails, inspect the file for hand-edited fields the steps cannot handle, fix or remove them, and re-run migrate.
Example fix
// before $ zeroclaw config set runtime.kind docker Error: config at ~/.config/zeroclaw/config.toml is schema_version 2; run `zeroclaw config migrate` to update before modifying // after $ zeroclaw config migrate $ zeroclaw config set runtime.kind docker // succeeds
Defensive patterns
Strategy: try-catch
Validate before calling
fn disk_version(raw: &str) -> Option<u32> {
toml::from_str::<toml::Value>(raw)
.ok()?
.get("schema_version")?
.as_integer()
.map(|v| v as u32)
}
if let Some(v) = disk_version(&raw) {
if v < 3 { /* run `zeroclaw config migrate` (with a backup) before modifying */ }
} Try / catch
match ensure_disk_at_current_version(&path) {
Err(e) if e.to_string().contains("zeroclaw config migrate") => {
// back up the file, run the migrate command, then retry the original call once
}
other => other?,
} Prevention
- Run `zeroclaw config migrate` immediately after upgrading across a schema bump.
- Never hand-edit schema_version; let the migration chain own it.
- Keep config migration as an explicit step in the upgrade runbook.
- Keep a pre-migration backup since the chain is forward-only.
When it happens
Trigger: A config whose detected schema_version is 1 or 2 is passed to any config-modifying entry point routed through ensure_disk_at_current_version. This is exactly what you hit after upgrading the binary across a schema boundary and trying to change settings before migrating.
Common situations: Upgrading ZeroClaw across a schema bump and editing settings before migrating; restoring an old config backup into a new install; sharing a config written by an older release.
Related errors
- config at {} is schema_version {from}, newer than this binar
- target V{target} exceeds CURRENT_SCHEMA_VERSION (V{CURRENT_S
- memory backend 'none' disables persistence; choose sqlite, l
- unsupported room visibility '{other}': expected private or p
- channel '{}' does not support forge API requests
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/f404a92aad607114.
Report an issue: GitHub.