Hmbown/CodeWhale · error · SecretsError::Io

could not resolve home directory for FileKeyringStore

Error message

could not resolve home directory for FileKeyringStore

What it means

FileKeyringStore cannot determine the user's home directory, so it cannot locate its secrets.json backing file. The secrets crate requires a home directory to derive the on-disk keyring store path (`$HOME/secrets/secrets.json`), and throws this NotFound io::Error wrapped in SecretsError when `dirs::home_dir()` (or equivalent) returns None.

Solutions

  1. Set the HOME environment variable to a writable directory the user owns (e.g. `export HOME=/home/user` or `Environment=HOME=/var/lib/service` in systemd).
  2. Ensure the user has a valid passwd entry with a home path (check `getent passwd $(whoami)`).
  3. In containers, create the home directory and pass it via `-e HOME=/home/app` and a mounted/created volume.
  4. If programmatic, use the store API that accepts an explicit root/path instead of relying on home resolution.

Example fix

// before (Dockerfile)
CMD ["codewhale"]

// after
ENV HOME=/home/app
RUN mkdir -p /home/app/secrets && chown -R app:app /home/app
CMD ["codewhale"]
Defensive patterns

Strategy: validation

Validate before calling

fn home_is_resolvable() -> bool {
    std::env::var_os("HOME").map(|h| !h.is_empty()).unwrap_or(false)
}
if !home_is_resolvable() {
    eprintln!("HOME is not set; FileKeyringStore will fail");
}

Type guard

fn has_home() -> Option<String> {
    std::env::var("HOME").ok().filter(|h| !h.is_empty())
}

Try / catch

match store.init() {
    Err(SecretsError::Io(e)) if e.kind() == std::io::ErrorKind::NotFound => {
        // home unresolvable: fall back to env-provided key or prompt user
    }
    other => other?,
}

Prevention

When it happens

Trigger: Constructing or using FileKeyringStore when the home directory cannot be resolved: `HOME` unset, `dirs::home_dir()` returning None, or running under a service account / sandboxed process with no home configured.

Common situations: Running the binary under systemd with no `$HOME`, inside Docker containers without `HOME` set, CI runners with stripped environments, or setuid/nonstandard users lacking a passwd entry.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/b9ea7216cae2c64d. Report an issue: GitHub.

Appendix: source

Thrown at crates/secrets/src/lib.rs:841

fn default_codewhale_secrets_path() -> Result<PathBuf, SecretsError> {
    Ok(codewhale_paths::codewhale_home()
        .map_err(|error| {
            SecretsError::Io(std::io::Error::new(std::io::ErrorKind::InvalidInput, error))
        })?
        .ok_or_else(home_resolution_error)?
        .join("secrets")
        .join("secrets.json"))
}

fn legacy_deepseek_secrets_path() -> Result<PathBuf, SecretsError> {
    Ok(codewhale_paths::legacy_deepseek_home()
        .ok_or_else(home_resolution_error)?
        .join("secrets")
        .join("secrets.json"))
}

fn home_resolution_error() -> SecretsError {
    SecretsError::Io(std::io::Error::new(
        std::io::ErrorKind::NotFound,
        "could not resolve home directory for FileKeyringStore",
    ))
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SecretBackendSelection {
    File,
    System,
    Unknown,
}

/// Secret-store backend selected by configuration for a structural diagnostic.
///
/// This type deliberately describes only configuration and filesystem shape.
/// It never implies that a provider credential exists.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]

View on GitHub (pinned to 73e0f67d83)