atuinsh/atuin · error
empty config key
Error message
empty config key
What it means
`set_deep_key` splits the config key on `.` and asserts at least one part exists before walking/creating nested TOML tables. Because `String::split('.')` on an empty string actually yields one empty part, this bail is effectively a defensive invariant guard for an empty/degenerate key reaching the function.
Solutions
- Always pass a non-empty key with at least one non-empty segment: `atuin config set theme.name dark`.
- Validate/trim the key before calling config-set logic.
- Prefer single-level keys like `atuin config set auto_sync true` when no nesting is needed.
Example fix
// before set_deep_key(doc, "", value) // bails: empty config key // after set_deep_key(doc, "theme.name", value)
Defensive patterns
Strategy: validation
Validate before calling
fn valid_key(k: &str) -> bool {
!k.is_empty() && k.split('.').all(|p| !p.is_empty())
} Type guard
fn valid_key(k: &str) -> bool {
!k.is_empty() && k.split('.').all(|p| !p.is_empty())
} Prevention
- Never construct keys from unvalidated user input.
- Reject keys that are empty or consist only of dots.
- Split on '.' and assert every segment is non-empty before calling set logic.
When it happens
Trigger: Calling `set_deep_key` with an empty or all-dot key path (e.g. "" or "."), reached via `config set` internal paths or `get_updated_config` when the key argument degenerates to nothing.
Common situations: Programmatic/plugin use of the set path with a malformed key; edge cases where a key consisting only of dots produces only empty parts.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- ' ' is a table; use a dotted key like ' .key' to set a…
- agent does not use JSON hooks
- Config key must be non-empty and must not contain whitespace
- Could not build config
- Could not build default
AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19).
Data as JSON: /api/errors/2093b598c05661ce.
Report an issue: GitHub.
Appendix: source
Thrown at crates/atuin/src/command/client/config.rs:323
if v.is_str() {
Some(ValueType::String)
} else if v.is_bool() {
Some(ValueType::Boolean)
} else if v.is_integer() {
Some(ValueType::Integer)
} else if v.is_float() {
Some(ValueType::Float)
} else {
None
}
}
fn set_deep_key(doc: &mut DocumentMut, key: &str, value: Value) -> Result<()> {
let parts: Vec<&str> = key.split('.').collect();
if parts.is_empty() {
eyre::bail!("empty config key");
}
let mut current: &mut dyn TableLike = doc.as_table_mut();
// Navigate/create intermediate tables
for &part in &parts[..parts.len() - 1] {
if !current.contains_key(part) {
current.insert(part, Item::Table(Table::new()));
}
current = current
.get_mut(part)
.expect("just inserted or already exists")
.as_table_like_mut()
.ok_or_else(|| eyre::eyre!("'{}' exists but is not a table", part))?;
}
let last = *parts.last().unwrap();
View on GitHub (pinned to 900007c480)