xai-org/grok-build · critical
refusing to overwrite unparseable {}: {}; save a backup and
Error message
refusing to overwrite unparseable {}: {}; save a backup and fix the syntax error before retrying What it means
save_config_locked refuses to write a new config over a file it cannot parse. Before saving, it re-reads user_config_path() and parses with parse_existing_config_toml; if parsing fails it aborts with this error rather than destroying the user's (possibly hand-modified) config with a syntax error. The message embeds the path and the parse error and asks the user to keep a backup and fix the syntax first.
Source
Thrown at crates/codegen/xai-grok-shell/src/util/config/persist.rs:27
/// Serializes the read-modify-write in `save_config` so two rapid
/// settings toggles can't interleave and clobber each other.
static SAVE_LOCK: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(());
/// Blank (first-run 0-byte file) is an empty table; other unparseable TOML is
/// an error so a silent fallback cannot drop unmodeled sections.
pub(crate) fn parse_existing_config_toml(s: &str) -> Result<TomlValue, toml::de::Error> {
if s.trim().is_empty() {
return Ok(TomlValue::Table(TomlMap::new()));
}
toml::from_str(s)
}
/// [`save_config`] body; caller must hold [`SAVE_LOCK`].
async fn save_config_locked(config: &Config) -> Result<()> {
let path = user_config_path();
let mut root: TomlValue = match tokio::fs::read_to_string(&path).await {
Ok(s) => match parse_existing_config_toml(&s) {
Ok(v) => v,
Err(parse_err) => {
return Err(anyhow::anyhow!(
"refusing to overwrite unparseable {}: {}; save a backup \
and fix the syntax error before retrying",
path.display(),
parse_err,
));
}
},
Err(_) => TomlValue::Table(TomlMap::new()),
};
if !matches!(root, TomlValue::Table(_)) {
root = TomlValue::Table(TomlMap::new());
}
let table = root.as_table_mut().expect("root must be a table");
merge_section(table, "cli", &config.cli);
merge_section(table, "models", &config.models);
merge_section(table, "ui", &config.ui);
merge_section(table, "harness", &config.harness);
merge_section(table, "session", &config.session);View on GitHub (pinned to bc7f02eddd)
Solutions
- Read the embedded parse_err in the message to find the file/line of the syntax error
- Copy the broken file to a backup (e.g. config.toml.bak) as the message instructs
- Fix the TOML syntax error at the reported location with an editor or `tomlcheck`
- Re-run update_config once the file parses cleanly
Example fix
# before (broken) model = "grok-4 max_tokens = 4096 # after model = "grok-4" max_tokens = 4096
Defensive patterns
Strategy: validation
Validate before calling
let s = tokio::fs::read_to_string(user_config_path()).await?;
if let Err(e) = s.parse::<toml::Value>() {
eprintln!("config unparseable: {e}; fix syntax before updating config");
} Type guard
fn parse_ok(s: &str) -> bool { s.parse::<toml::Value>().is_ok() } Try / catch
match update_config(|cfg| { /* mutation */ }).await {
Err(e) if e.to_string().contains("refusing to overwrite unparseable") => {
std::fs::copy(&cfg_path, "config.toml.bak")?;
eprintln!("backed up broken config; fix the TOML syntax error and retry");
}
other => other,
} Prevention
- Validate config.toml after every manual edit (tomlcheck / parse test)
- Keep backups before editing config by hand
- Never force-overwrite a config file that fails to parse
- Add CI checks that parse the shipped/default config
When it happens
Trigger: Calling update_config while the existing user config TOML on disk has a parse error (malformed TOML, invalid types in an already-passed section, stray characters), so the preservation of existing content cannot be guaranteed.
Common situations: A manual edit to config.toml introduced a typo; a comment containing an unescaped control character; a merge tool or script mangled the file; encoding issues (non-UTF8 bytes) after an editor or tool rewrote it.
Related errors
- Failed to parse config.toml: {e}
- refusing to write import marker: existing config at {} is no
- refusing to import: existing config at {} is not valid TOML
- refusing to overwrite unparseable {}: {}; fix the syntax bef
- refusing to rewrite unparseable {}: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/9a0958ad799dbee0.
Report an issue: GitHub.