Hmbown/CodeWhale · error · anyhow::Error
must not be empty
Error message
{kind} must not be empty What it means
ensure_safe_storage_id validates that a storage identifier (kind describes which field, e.g. automation id or run id) is usable as a filename. An empty string yields no first path component, so it is rejected with this error before it can produce an invalid or colliding storage path.
Solutions
- Ensure the id is generated/non-empty before calling the storage API (e.g. reject empty input in the caller or use a UUID).
- Fix the form/deserialization path that produced an empty id.
- Add a caller-side check that !id.is_empty() before persisting.
Example fix
// before
store.save_run("")?;
// after
if run_id.is_empty() { return Err(anyhow!("run id must not be empty")); }
store.save_run(run_id)?; Defensive patterns
Strategy: validation
Validate before calling
if id.is_empty() || Path::new(id).components().next().is_none() {
return Err(anyhow!("{kind} must not be empty"));
} Type guard
fn is_safe_storage_id(id: &str) -> bool {
let mut c = Path::new(id).components();
matches!(c.next(), Some(std::path::Component::Normal(_))) && c.next().is_none()
} Try / catch
match ensure_safe_storage_id("run id", &id) {
Ok(()) => store.save_run(&id, run)?,
Err(e) => regenerate_id_and_retry(),
} Prevention
- Generate ids with a UUID or slug generator instead of accepting free-form input.
- Validate ids at the point of creation, not only at storage time.
- Reject empty form fields before they become record ids.
When it happens
Trigger: Passing an empty string (or a value that Path::new sees as having no Normal components, like "" ) as an id to a save/load automation or run API.
Common situations: An id field left unset/empty in a deserialized record or UI form; trimming a name down to nothing before deriving an id; a generator bug producing empty ids.
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
- budget baseline_receipt path changed
- Codewhale credentials directory has an unsupported component
- Codewhale credentials directory must be lexically normalized
- config path cannot be empty
- config path cannot contain '..' components
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/326abf7b2ca79599.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/automation_manager.rs:2777
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 73e0f67d83)