Hmbown/CodeWhale · error

Failed to resolve settings path: no config directory found.

Error message

Failed to resolve settings path: no config directory found.

What it means

`Settings::path()` resolves where settings.toml should live by taking the first available candidate among the primary (~/.codewhale/settings.toml style) home-based path and the legacy config directory. If neither the home directory nor any config directory can be determined (e.g. no HOME/XDG_CONFIG_HOME and no resolvable profile directory), there is nowhere to read or write settings and this error is returned.

Solutions

  1. Set the HOME environment variable (or USERPROFILE on Windows) to a writable directory before launching
  2. Set XDG_CONFIG_HOME to an existing writable directory so the primary candidate resolves
  3. Run the process as a real user account that has a home directory, or pre-create the home dir

Example fix

// before: spawned without HOME
let path = Settings::path()?; // Err: no config directory found
// after: ensure env before launch
std::env::set_var("HOME", "/home/deploy");
std::fs::create_dir_all("/home/deploy/.codewhale")?;
let path = Settings::path()?;
Defensive patterns

Strategy: fallback

Validate before calling

let has_home = std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE")).is_some()
    || std::env::var_os("XDG_CONFIG_HOME").is_some();
if !has_home { eprintln!("no config directory resolvable"); }

Try / catch

match Settings::path() {
    Ok(p) => p,
    Err(e) => { eprintln!("set HOME or XDG_CONFIG_HOME: {e}"); std::process::exit(2); }
}

Prevention

When it happens

Trigger: Calling Settings::path() (public) in an environment where the user's home directory and the system config directory are both unresolvable: HOME unset, XDG_CONFIG_HOME unset, no passwd entry, or a service/CI context without a user profile.

Common situations: Running the TUI in a bare Docker container or systemd service with no HOME set; CI jobs with a stripped environment; cron jobs missing env; running as a user without a home directory.

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/e4cfa7649711bbef. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/settings.rs:747

/// `/config preset` command so the bundle is never defined twice.
#[must_use]
pub fn preset_fields(name: &str) -> Option<&'static [(&'static str, &'static str)]> {
    match name.trim().to_ascii_lowercase().as_str() {
        "calm" => Some(CALM_PRESET_FIELDS),
        _ => None,
    }
}

impl Settings {
    /// Get the canonical settings file path.
    ///
    /// New writes should target `~/.codewhale/settings.toml`. Legacy
    /// DeepSeek-branded paths remain readable as fallbacks during load, but we
    /// no longer surface them as the primary path in `/config`.
    pub fn path() -> Result<PathBuf> {
        let (primary, _legacy_home, legacy_config_dir) = settings_path_candidates();
        primary.or(legacy_config_dir).ok_or_else(|| {
            anyhow::anyhow!("Failed to resolve settings path: no config directory found.")
        })
    }

    /// Load settings from disk, or return defaults if not found
    pub fn load() -> Result<Self> {
        let mut settings = Self::load_persisted()?;
        settings.apply_env_overrides();
        Ok(settings)
    }

    /// Load settings for a diagnostic without migrating a legacy file.
    ///
    /// This preserves the same candidate precedence, parser normalization, and
    /// environment overlays as [`Settings::load`]. Unlike an interactive
    /// startup, diagnostics must not create `~/.codewhale/settings.toml` just
    /// because they inspected a legacy `~/.deepseek/settings.toml` file.
    pub(crate) fn load_read_only() -> Result<Self> {
        let mut settings = Self::load_persisted_read_only()?;

View on GitHub (pinned to 73e0f67d83)