{"record":{"id":"8bd88fed36c826b3","repo":"Hmbown/CodeWhale","slug":"failed-to-parse-config-toml-while-removing-plainte","errorCode":null,"errorMessage":"failed to parse config TOML while removing plaintext API keys; file contents were omitted","messagePattern":"failed to parse config TOML while removing plaintext API keys; file contents were omitted","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/config/src/lib.rs","lineNumber":5298,"sourceCode":"            \"failed to scrub plaintext API keys while creating config backup {}\",\n            backup.display()\n        )\n    })?;\n    persistence::atomic_write(&backup, scrubbed.as_bytes()).with_context(|| {\n        format!(\n            \"failed to create credential-free config backup {} from {}\",\n            backup.display(),\n            path.display()\n        )\n    })?;\n    Ok(())\n}\n\nfn config_toml_without_plaintext_api_keys(raw: &str) -> Result<String> {\n    let mut document = raw\n        .parse::<toml_edit::DocumentMut>()\n        .map_err(|_| {\n            anyhow::anyhow!(\n                \"failed to parse config TOML while removing plaintext API keys; file contents were omitted\"\n            )\n        })?;\n    remove_plaintext_api_keys_recursive(document.as_table_mut());\n    Ok(document.to_string())\n}\n\nfn remove_plaintext_api_keys_recursive(table: &mut dyn toml_edit::TableLike) {\n    table.remove(\"api_key\");\n    for (_, item) in table.iter_mut() {\n        if let toml_edit::Item::ArrayOfTables(tables) = item {\n            for nested in tables.iter_mut() {\n                remove_plaintext_api_keys_recursive(nested);\n            }\n        } else if let Some(nested) = item.as_table_like_mut() {\n            remove_plaintext_api_keys_recursive(nested);\n        }\n    }","sourceCodeStart":5280,"sourceCodeEnd":5316,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/config/src/lib.rs#L5280-L5316","documentation":"Before writing a credential-free config backup, Codewhale re-parses the raw config with toml_edit to recursively strip plaintext api_key entries. If the file is not valid TOML, redaction is refused with this message; contents are omitted so keys never reach logs.","triggerScenarios":"The backup/redaction flow (config_toml_without_plaintext_api_keys) runs when plaintext API keys exist in the config and the file has a TOML syntax error or duplicate keys, so a safe sanitized copy cannot be produced.","commonSituations":"A user hand-edited the config and broke syntax while an api_key was present; an interrupted write truncated the file; the redaction then blocks until the file parses.","solutions":["Fix the TOML syntax first (validator or TOML-aware editor), then re-trigger the operation","If you need the rewrite regardless, temporarily remove the plaintext api_key lines yourself and retry","Restore from the pre-edit backup if one exists"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before triggering the credential-free backup, prove the raw config parses:\nfn raw_config_parses(raw: &str) -> bool {\n    raw.parse::<toml_edit::DocumentMut>().is_ok()\n}","typeGuard":null,"tryCatchPattern":"On Err, keep the original file untouched (the code already refuses to write) and direct the user to fix the TOML; redaction cannot be forced, so the catch flow is repair-then-retry once.","preventionTips":["Remove plaintext api_key entries before hand-editing the config, so redaction never has to run on a broken file","Keep backups of the config before editing"],"tags":["config","toml","parse","secrets","backup"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}