rust-lang/cargo · error
expected table for configuration key
Error message
expected table for configuration key `{}`, but found {} in {} What it means
Cargo raises this hard error when resolving a configuration key whose intermediate value must be a table (e.g. `target.x.y` or `[foo]` sections) but the stored value is a scalar (integer, string, list, or boolean) instead. It is thrown in get_cv_helper while walking the config key path: a prefix of the requested key resolved to a non-table CV variant, so a nested key cannot exist beneath it. The message names the truncated key, the found value's description, and the file:line where that value was defined.
Solutions
- Open the config file named in the error (the `in <file>` part) and change the scalar value into a TOML table, e.g. replace `target = "..."` with a `[target."<triple>"]` section.
- Check for duplicate definitions across all config sources (system, global ~/.cargo/config.toml, project .cargo/config.toml) and remove the one that defines the key as a scalar.
- Verify quoting for keys that contain hyphens or dots, e.g. [target.'cfg(all(unix, target_arch = "x86_64"))'].
Example fix
// before: .cargo/config.toml target = "x86_64-unknown-linux-gnu" // after: .cargo/config.toml [target.x86_64-unknown-linux-gnu] linker = "clang"
Defensive patterns
Strategy: validation
Validate before calling
// TOML / shell check before invoking cargo grep -n '^\s*target\s*=' ~/.cargo/config.toml .cargo/config.toml 2>/dev/null || true # any hit means `target` (or the failing key prefix) is a scalar, not a table — fix it
Type guard
fn is_table(v: &toml::Value) -> bool { matches!(v, toml::Value::Table(_)) } Try / catch
match gctx.get::<String>(&["target", triple, "linker"]) {
Err(e) if e.to_string().contains("expected table for configuration key") => {
// fall back to default / repair config
}
other => other?,
} Prevention
- Never define section names (`target`, `registry`, `source`) as scalar keys; always use table syntax.
- Keep one canonical config file per scope to avoid cross-source key collisions.
- Quote complex key expressions (cfg(...) strings) correctly inside table headers.
When it happens
Trigger: Calling config lookups such as gctx.get(...) with a multi-part key (e.g. ["target", "x86_64-unknown-linux-gnu", "linker"]) where a prefix like `target` or `target.<triple>` was defined in a config file as a scalar — for example `target = "x86_64-linux"` instead of `target."x86_64-..." = ...`, or a `[foo]` table accidentally overridden by a `foo = ...` scalar in a later config source.
Common situations: Typos or wrong nesting in ~/.cargo/config.toml or .cargo/config.toml (defining `target` as a string instead of a table); merging config sources where one file uses TOML key syntax `foo = value` and another uses `[foo]` tables, silently replacing the table with a scalar; environment-variable-based config where dotted names don't produce nested tables.
Related errors
- ` ` expected , but found a
- failed to merge config value from
- missing config key
- can't find library ` `, rename file to `src/lib.rs` or…
- cannot mix `proc-macro` crate type with others
AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-09-22).
Data as JSON: /api/errors/f7ab5251e87c92a7.
Report an issue: GitHub.
Appendix: source
Thrown at src/context/mod.rs:871
}
let mut parts = key.parts().enumerate();
let Some(mut val) = vals.get(parts.next().unwrap().1) else {
return Ok(None);
};
for (i, part) in parts {
match val {
CV::Table(map, _) => {
val = match map.get(part) {
Some(val) => val,
None => return Ok(None),
}
}
CV::Integer(_, def)
| CV::String(_, def)
| CV::List(_, def)
| CV::Boolean(_, def) => {
let key_so_far = ConfigKey::from_parts(key.parts().take(i));
bail!(
"expected table for configuration key `{}`, \
but found {} in {}",
key_so_far,
val.desc(),
def
)
}
}
}
Ok(Some(val.clone()))
}
/// This is a helper for getting a CV from a file or env var.
pub(crate) fn get_cv_with_env(&self, key: &ConfigKey) -> CargoResult<Option<CV>> {
// Determine if value comes from env, cli, or file, and merge env if
// possible.
let cv = self.get_cv(key)?;
if key.is_root() {View on GitHub (pinned to 98a09e7e7d)