Hmbown/CodeWhale · error · anyhow::Error

failed to parse config at {}; file contents were omitted

Error message

failed to parse config at {}; file contents were omitted

What it means

mutate_config_document takes the shared config write lock, parses the existing file with toml_edit, applies a mutation, and persists only the delta. This error means the on-disk file failed TOML parsing, so the mutation aborted before any write. File contents are deliberately omitted from the message so config secrets never reach logs.

Source

Thrown at crates/config/src/config_document.rs:30

use anyhow::{Context, Result, bail};

use crate::{
    checked_path_exists, normalize_config_file_path, persistence, read_checked_config_file,
    write_one_time_config_backup,
};

/// Parse the latest document under the shared write lock, apply `mutate`, and
/// atomically persist only the resulting delta.
pub fn mutate_config_document<T, F>(path: &Path, mutate: F) -> Result<T>
where
    F: FnOnce(&mut toml_edit::DocumentMut) -> Result<T>,
{
    with_config_write_lock(path, |path| {
        let original = read_optional_config(path)?;
        let mut document = match original.as_deref() {
            Some(raw) if !raw.trim().is_empty() => {
                raw.parse::<toml_edit::DocumentMut>().map_err(|_| {
                    anyhow::anyhow!(
                        "failed to parse config at {}; file contents were omitted",
                        crate::quote_os_path(path)
                    )
                })?
            }
            _ => toml_edit::DocumentMut::new(),
        };
        heal_extras_nesting(&mut document);
        let result = mutate(&mut document)?;
        let body = document.to_string();
        if original.as_deref() == Some(body.as_str()) || (original.is_none() && body.is_empty()) {
            return Ok(result);
        }
        persist_locked(path, original.as_deref(), body.as_bytes())?;
        Ok(result)
    })
}

View on GitHub (pinned to 8880682c63)

Solutions

  1. Validate the file with a TOML checker (taplo check or an editor TOML LSP) and fix the reported line
  2. Check for duplicate keys: TOML forbids them; rename one of the duplicates
  3. If unfixable, back the file up and move it aside so defaults regenerate, then reapply settings from the backup

Example fix

# before (config.toml with a duplicate key)
model = "glm-4.6"
theme = "dark"
model = "glm-4.7"   # error: duplicate key

# after
model = "glm-4.7"
theme = "dark"
Defensive patterns

Strategy: validation

Validate before calling

// Before calling mutate_config_document, prove the file parses:
fn config_is_editable(path: &std::path::Path) -> bool {
    match std::fs::read_to_string(path) {
        Ok(raw) => raw.trim().is_empty() || raw.parse::<toml_edit::DocumentMut>().is_ok(),
        Err(_) => false,
    }
}

Try / catch

On Err, stop and point the user at a TOML validator output for the quoted path; do not retry, the file will not parse differently. Offer the move-aside-and-regenerate path explicitly.

Prevention

When it happens

Trigger: Any config-mutating API call while the file contains invalid TOML syntax (unclosed string/bracket, malformed inline table) or duplicate keys, which toml_edit rejects, even when the pending mutation itself would be valid.

Common situations: Hand-edited config.toml with a typo; a crashed process leaving a truncated file; merge-conflict resolution introducing a duplicate key; another tool appending malformed lines.

Understand the failure class

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/00cd1376009ef8b6. Report an issue: GitHub.