Hmbown/CodeWhale · error · anyhow::Error

Runtime store root cannot be empty

Error message

Runtime store root cannot be empty

What it means

checked_runtime_store_root validates the runtime store root before any filesystem use and rejects an empty path (crates/tui/src/runtime_threads.rs:8857). An empty root would resolve to ambiguous relative locations and corrupt store layout, so the constructor fails fast.

Source

Thrown at crates/tui/src/runtime_threads.rs:8857

        0
    } else {
        u64::try_from(millis).unwrap_or(u64::MAX)
    }
}

fn panic_payload_message(payload: &(dyn std::any::Any + Send)) -> String {
    if let Some(message) = payload.downcast_ref::<&str>() {
        (*message).to_string()
    } else if let Some(message) = payload.downcast_ref::<String>() {
        message.clone()
    } else {
        "unknown panic payload".to_string()
    }
}

fn checked_runtime_store_root(root: PathBuf) -> Result<PathBuf> {
    if root.as_os_str().is_empty() {
        bail!("Runtime store root cannot be empty");
    }
    if root
        .components()
        .any(|component| matches!(component, Component::ParentDir))
    {
        bail!("Runtime store root cannot contain '..' components");
    }
    let absolute = if root.is_absolute() {
        root
    } else {
        std::env::current_dir()
            .context("failed to resolve current directory for runtime store")?
            .join(root)
    };
    match absolute.canonicalize() {
        Ok(path) => Ok(path),
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
            Ok(normalize_path_components(&absolute))

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Set an explicit non-empty store root path in config/environment
  2. Treat an empty env var as unset and fall back to the documented default location
  3. Validate the resolved path at startup before constructing the runtime
  4. Use an absolute path to avoid dependence on the process working directory

Example fix

// before
let root = PathBuf::from(std::env::var(\"CODEWHALE_STORE_ROOT\").unwrap_or_default());

// after
let root = std::env::var("CODEWHALE_STORE_ROOT")
    .ok()
    .filter(|v| !v.trim().is_empty())               // empty means unset
    .map(PathBuf::from)
    .unwrap_or_else(|| default_store_root());
Defensive patterns

Strategy: validation

Validate before calling

// Validate before constructing the runtime.
let raw = std::env::var("CODEWHALE_STORE_ROOT").ok()
    .filter(|v| !v.trim().is_empty());
let root: PathBuf = raw.map(PathBuf::from)
    .unwrap_or_else(default_store_root);
assert!(!root.as_os_str().is_empty(), "store root must not be empty");

Type guard

fn is_nonempty_root(root: &Path) -> bool {
    !root.as_os_str().is_empty()
}

Try / catch

match RuntimeStore::open(root) {
    Ok(store) => store,
    Err(err) if err.to_string().contains("store root cannot be empty") => {
        RuntimeStore::open(default_store_root()).expect("default store root must be valid")
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: An env var for the store root set but empty (VAR= with nothing after); a config default missing after an upgrade so "" propagates; code passing PathBuf::from("") or PathBuf::new() when a lookup fails

Common situations: Dotfiles exporting empty env vars; CI templates that define the variable without a value; refactors that default to an empty string instead of a real path; fresh machines without the configured directory.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/37d9322233a2cbf9. Report an issue: GitHub.