Kuberwastaken/claurst · error · anyhow::Error
Refusing to overwrite malformed settings file
Error message
Refusing to overwrite malformed settings file {}: {} What it means
The async settings save path (`save_to_path`) refuses to overwrite an existing settings file whose current contents do not parse as valid JSON. This is a safety guard: if the file is malformed (possibly due to a crash or user edit), rewriting it would silently destroy the user's configuration, so the save aborts instead.
Solutions
- Fix or remove the malformed settings.json at the path shown (back it up first), then retry the save.
- Validate the existing file with `jq . settings.json` to locate the syntax error and repair it before re-running the save.
- If the file is unrecoverable, delete it so the next save starts from a fresh valid file.
Example fix
cp settings.json settings.json.broken
jq . settings.json # shows exact syntax error
echo '{}' > settings.json # reset after backup if unrecoverable Defensive patterns
Strategy: validation
Validate before calling
// before calling an async save, ensure the current file parses:
let path = Settings::global_settings_path();
if path.exists() {
let content = tokio::fs::read_to_string(&path).await?;
serde_json::from_str::<serde_json::Value>(&content)
.map_err(|e| anyhow::anyhow!("settings.json is malformed, repair before saving: {e}"))?;
} Type guard
fn settings_file_parseable(content: &str) -> bool {
serde_json::from_str::<serde_json::Value>(content).is_ok()
} Try / catch
match settings.save().await {
Err(e) if e.to_string().contains("Refusing to overwrite malformed") => {
eprintln!("{e:#}"); eprintln!("Repair or delete settings.json, then retry.");
}
other => other?,
} Prevention
- Repair settings.json immediately after any parse error on load — don't keep running with a broken file.
- Avoid writing settings.json with scripts that don't validate output; serialize through serde_json instead of string concatenation.
- Check for crashed/interrupted writes (partial files) and delete truncated files.
- Back up settings.json before bulk edits.
When it happens
Trigger: Calling any async settings-save API (e.g. persisting updated settings) where `path.exists()` and the on-disk content fails `Settings::parse_file` — i.e. the existing settings.json is invalid JSON or has the wrong shape for the settings struct.
Common situations: The user hand-edited settings.json and broke the syntax, then the app or a TUI command tries to persist a setting; a previous write was truncated mid-flight leaving corrupt JSON; an external tool replaced the file with non-JSON content.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- source settings.json must be a JSON object
- Failed to parse settings file
- Bridge register: auth error
- Bridge poll: auth error
- Bridge session registration failed: authentication error
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/0b32f2ae49d07284.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/core/src/lib.rs:1745
} else {
Ok(Self::default())
}
}
fn load_from_path_sync(path: &Path) -> anyhow::Result<Self> {
if path.exists() {
let content = std::fs::read_to_string(path)?;
Self::parse_file(&content, path)
} else {
Ok(Self::default())
}
}
async fn save_to_path(&self, path: &Path) -> anyhow::Result<()> {
if path.exists() {
let content = tokio::fs::read_to_string(path).await?;
Self::parse_file(&content, path).map_err(|error| {
anyhow::anyhow!(
"Refusing to overwrite malformed settings file {}: {}",
path.display(),
error
)
})?;
}
if let Some(parent) = path.parent() {
tokio::fs::create_dir_all(parent).await?;
}
let content = serde_json::to_string_pretty(self)?;
tokio::fs::write(path, content).await?;
Ok(())
}
fn save_to_path_sync(&self, path: &Path) -> anyhow::Result<()> {
if path.exists() {
let content = std::fs::read_to_string(path)?;
Self::parse_file(&content, path).map_err(|error| {View on GitHub (pinned to b0637c97ec)