Hmbown/CodeWhale · error
serialized typed config was not valid TOML
Error message
serialized typed config was not valid TOML
What it means
config_document round-trips the typed ConfigToml through TOML text (to avoid double-encoding datetime values via Value::try_from) and then parses it back to a toml::Value. If that reparse fails, the serializer produced text that is not valid TOML — an internal invariant violation, since toml::to_string output should always reparse. The error deliberately carries no config contents.
Solutions
- Simplify the config: remove unusual/unknown keys or exotic value types from the config file and retry.
- Check for a toml crate version mismatch or known round-trip bug; update the dependency.
- Report the offending config shape as a bug — this path should never fail for valid typed config.
- Validate the config file parses as TOML on its own before exporting/importing.
Example fix
// before (config.toml) [weird] key = 1979-05-27T07:32:00Z-extra // after (config.toml) [weird] key = 1979-05-27T07:32:00Z
Defensive patterns
Strategy: try-catch
Validate before calling
let raw = std::fs::read_to_string(config_path)?; let _probe: toml::Value = toml::from_str(&raw).expect("base config must be valid TOML"); Try / catch
match export_bundle(...) { Err(e) if e.to_string().contains("was not valid TOML") => eprintln!("internal round-trip bug; simplify config and report"), other => other, } Prevention
- Keep the config file free of unknown/exotic keys.
- Keep the toml crate at a consistent version.
- Validate config.toml parses before export/import operations.
- Report reproducible shapes as bugs — this is an invariant path.
When it happens
Trigger: toml::from_str on the output of toml::to_string(config) fails inside config_document, which is invoked by export_bundle, prepare_import, and config value inspection helpers.
Common situations: A ConfigToml containing exotic flattened toml::Value extras or unusual value types that the serializer renders in a form the parser rejects — practically a bug in the interaction between the typed config and the toml crate version in use.
Related errors
- could not prepare imported configuration; contents omitted
- failed to parse serialized config for comment merge; file…
- active profile is missing or malformed
- Cannot export a non-string default_model without losing its…
- Cannot export a root model alias into a non-table provider…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/9c81304dbdcaff05.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/config_bundles.rs:966
if key.starts_with("skills") || key.starts_with("tools") || key.starts_with("snapshots") {
return ExportSection::Preferences;
}
if key.starts_with("auth.") {
return ExportSection::Drop;
}
match scope {
BundleScope::Global => ExportSection::Global,
BundleScope::Project => ExportSection::Project,
}
}
fn config_document(config: &ConfigToml) -> Result<toml::map::Map<String, toml::Value>> {
// Serialize through TOML text before parsing to Value. Direct
// `Value::try_from` double-encodes datetime values held inside flattened
// `toml::Value` extras as the serializer's private marker table.
let text = toml::to_string(config).context("serializing typed config for bundle")?;
let value: toml::Value =
toml::from_str(&text).map_err(|_| anyhow!("serialized typed config was not valid TOML"))?;
let toml::Value::Table(mut table) = value else {
bail!("typed config did not serialize to a TOML table");
};
// `selected_provider_id` is runtime parse state and is skipped by serde;
// restore the exact named-provider identity that ConfigStore writes.
table.insert(
"provider".to_string(),
toml::Value::String(config.provider_id().to_string()),
);
Ok(table)
}
/// Return a recursively scrubbed export value. Secret-bearing leaves and
/// machine-local paths are omitted rather than replaced with a placeholder,
/// because a placeholder would become literal config on re-import.
fn sanitize_export_value(path: &str, value: &toml::Value) -> Option<toml::Value> {
sanitize_export_value_at(path, value, 0)
}View on GitHub (pinned to 73e0f67d83)