Hmbown/CodeWhale · error
typed config did not serialize to a TOML table
Error message
typed config did not serialize to a TOML table
What it means
config_document serializes the typed ConfigToml to TOML, re-parses it, and expects the top-level value to be a table. If toml::to_string produced anything other than a root table (an internal invariant — a struct always serializes to a table), the export/import pipeline bails rather than proceeding with a malformed document. The round-trip exists to avoid double-encoding datetime values held in flattened extras.
Solutions
- Inspect the config file for structurally invalid top-level content (an array or bare value instead of key/value sections) and fix it.
- Verify the codewhale-config crate version matches the CLI; a mismatched pair can change serialization shape.
- If it reproduces with a stock config, report it as a bug — this path is an internal invariant, not user input validation.
- Regenerate a clean config (back up first) and retry the export/import.
Example fix
// before (config.toml root) [[somewhere]] key = "value" // after (root must be a table of sections) [provider] id = "openai"
Defensive patterns
Strategy: try-catch
Type guard
if let toml::Value::Table(table) = &parsed {
// proceed with table
} Try / catch
match config_document(config) {
Ok(doc) => { /* use doc */ }
Err(e) if e.to_string().contains("did not serialize to a TOML table") => {
eprintln!("serialization invariant broken; check codewhale-config version / config shape: {e:#}");
}
Err(e) => return Err(e),
} Prevention
- Keep codewhale-config and the CLI on matching versions.
- Avoid hand-editing the top-level structure of config.toml into non-table shapes.
- Treat reproducible occurrences of this error as a bug report, not a config problem.
When it happens
Trigger: export_bundle, prepare_import, or apply_config_value calls config_document and the toml round-trip yields a non-table root — essentially only possible when the serialized output is an array or scalar, which for ConfigToml would indicate a serde/serialization bug or a corrupted typed config.
Common situations: Rare: a codewhale-config version change altering the serializer's output shape; a hand-edited or corrupted config source that deserializes into an unexpected shape; a bug in custom serde impls.
Related errors
- bundle contains conflicting or rejected entries
- could not prepare imported configuration; contents omitted
- failed to parse serialized config for comment merge; file…
- rendered body
- serialized typed config was not valid TOML
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/54f3a231a8026e90.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/config_bundles.rs:968
}
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)
}
fn sanitize_export_value_at(path: &str, value: &toml::Value, depth: usize) -> Option<toml::Value> {View on GitHub (pinned to 73e0f67d83)