Hmbown/CodeWhale · error · anyhow::Error
{kind} must not be empty
Error message
{kind} must not be empty What it means
ensure_safe_storage_id validates identifiers that become file names under the automation and task storage trees. It splits the value as a path and bails with '{kind} must not be empty' when the string yields zero path components — an empty id. The {kind} placeholder names the exact field at the call site: 'automation id', 'trigger id', 'run id', or 'task id'.
Source
Thrown at crates/tui/src/automation_manager.rs:1834
fn read_run_file(path: &Path) -> Result<AutomationRunRecord> {
let raw =
fs::read_to_string(path).with_context(|| format!("Failed to read {}", path.display()))?;
let run: AutomationRunRecord = serde_json::from_str(&raw)
.with_context(|| format!("Failed to parse {}", path.display()))?;
if run.schema_version > CURRENT_RUN_SCHEMA_VERSION {
bail!(
"Automation run schema v{} is newer than supported v{}",
run.schema_version,
CURRENT_RUN_SCHEMA_VERSION
);
}
Ok(run)
}
fn ensure_safe_storage_id(kind: &str, value: &str) -> Result<()> {
let mut components = Path::new(value).components();
let Some(component) = components.next() else {
bail!("{kind} must not be empty");
};
if components.next().is_some() || !matches!(component, std::path::Component::Normal(_)) {
bail!("{kind} must be a single path component");
}
Ok(())
}
fn validate_name_and_prompt(name: &str, prompt: &str) -> Result<()> {
if name.trim().is_empty() {
bail!("Automation name is required");
}
if prompt.trim().is_empty() {
bail!("Automation prompt is required");
}
Ok(())
}
fn normalize_optional_string(value: Option<String>) -> Option<String> {View on GitHub (pinned to 0c42157ee5)
Solutions
- Populate the id before the call — generate a uuid or slug at record creation time.
- If the id derives from a user-entered name, validate the name is non-empty before building the record.
- Use the {kind} text in the message to identify exactly which field was empty.
Example fix
// before
let record = DelayedTriggerRecord {
trigger_id: String::new(), // never populated
// ..remaining fields
};
manager.save_trigger(&record)?; // bails: trigger id must not be empty
// after
let record = DelayedTriggerRecord {
trigger_id: uuid::Uuid::new_v4().simple().to_string(),
// ..remaining fields
};
manager.save_trigger(&record)?; Defensive patterns
Strategy: validation
Validate before calling
fn non_empty_storage_id(id: &str) -> bool {
!id.trim().is_empty()
} Prevention
- Generate ids at record construction; never default them to empty.
- Add required-field checks in the UI/CLI before persistence calls.
- Fail loudly when an id generator returns empty instead of propagating it.
When it happens
Trigger: Saving or addressing an automation, trigger, run, or task with an empty id string — e.g. a record built with an uninitialized or trimmed-to-empty id passed to the save/get/delete entry points that call ensure_safe_storage_id (automation_manager.rs lines ~920-949).
Common situations: Struct literals with placeholder ids (String::new()) reaching a save path; ids derived from user-supplied names that were blank; an upstream id generator returning empty and the failure being swallowed before the store call.
Related errors
- Automation name cannot be empty
- Automation prompt cannot be empty
- {kind} must be a single path component
- Automation name is required
- Automation prompt is required
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/326abf7b2ca79599.
Report an issue: GitHub.