xai-org/grok-build · error
refusing to overwrite unparseable {}: {}; fix the syntax bef
Error message
refusing to overwrite unparseable {}: {}; fix the syntax before retrying What it means
write_toml_table_if_changed refuses to rewrite a config file whose contents cannot be parsed as TOML, protecting hand-edited or corrupted configs from being clobbered by a generated write. The error carries both the path and the parse error and instructs the user to fix the syntax first.
Source
Thrown at crates/codegen/xai-grok-shell/src/util/config/mcp.rs:792
let is_user = path == config_path().as_path();
let _guard = if is_user {
Some(super::persist::lock_config_writes().await)
} else {
None
};
let original = match tokio::fs::read_to_string(path).await {
Ok(s) => s,
Err(e) if e.kind() == std::io::ErrorKind::NotFound && is_user => String::new(),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(false),
Err(e) => {
return Err(anyhow::anyhow!("failed to read {}: {e}", path.display()));
}
};
let mut root = match super::persist::parse_existing_config_toml(&original) {
Ok(v) => v,
Err(parse_err) => {
return Err(anyhow::anyhow!(
"refusing to overwrite unparseable {}: {}; fix the syntax before retrying",
path.display(),
parse_err
));
}
};
let before = toml::to_string_pretty(&root)?;
let table = root
.as_table_mut()
.ok_or_else(|| anyhow::anyhow!("config root is not a table"))?;
f(table);
let toml_str = toml::to_string_pretty(&root)?;
if before == toml_str {
return Ok(false);
}
super::persist::atomic_write_string(path, &toml_str)
.map_err(|e| anyhow::anyhow!("failed to write {}: {e}", path.display()))?;
Ok(true)View on GitHub (pinned to bc7f02eddd)
Solutions
- Open the file at the reported path, fix the TOML syntax error shown after the semicolon, then retry the save.
- Keep a backup: copy the file aside, delete it so the tool writes a clean one, and re-apply settings manually.
- Validate with a TOML parser/linter (`cargo add toml` one-off script or an editor TOML plugin) before retrying.
- Check for duplicate/conflicting keys or a truncated file if the parse error is cryptic.
Example fix
# before (invalid TOML) [mcp_servers] name = "x # after (fixed) [mcp_servers.x] command = "npx" args = ["-y", "server"]
Defensive patterns
Strategy: validation
Validate before calling
fn toml_parses(path: &Path) -> Result<(), String> {
let s = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
s.parse::<toml::Value>().map(|_| ()).map_err(|e| e.to_string())
}
// guard: if toml_parses(&cfg_path).is_err() { fix syntax before saving } Try / catch
match save_mcp_server_enabled_in(&cfg_path, name, enabled).await {
Err(e) if e.to_string().contains("refusing to overwrite unparseable") => {
let backup = cfg_path.with_extension("toml.bak");
std::fs::copy(&cfg_path, &backup)?; // preserve user edits
eprintln!("fix TOML syntax in {} (backup at {})", cfg_path.display(), backup.display());
Err(e)
}
other => other,
} Prevention
- Run a TOML linter/parser after every manual config edit
- Keep backups (.bak) before programmatic config rewrites
- Never paste non-TOML content into the config path
- Watch for truncated writes from crashes; the guard prevents silent data loss
When it happens
Trigger: Calling save_mcp_server_enabled_in / save_user_mcp_server_enabled when parse_existing_config_toml fails on the existing file — i.e. the file exists but contains invalid TOML.
Common situations: A manual edit left a syntax error (unclosed string, bad table header, duplicate keys the parser rejects); a partially written file from an earlier crash; a non-TOML file placed at the config path.
Related errors
- Failed to load config: {e}
- 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
- config root is not a table
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/60d2fe27ce3afbef.
Report an issue: GitHub.