Hmbown/CodeWhale · error

Cannot resolve the user-global model configuration.

Error message

Cannot resolve the user-global model configuration.

What it means

`try_persist_route_as_startup_default` persists the chosen provider/model as the user-global startup default by writing to the user's home config file. `crate::config::home_config_path()` returns Option and None means no home config directory could be resolved, so persistence aborts with this error.

Solutions

  1. Set HOME to a writable directory before launching the app
  2. Create/verify the user config directory exists and is writable
  3. Skip persisting the startup default and set it per-session instead

Example fix

// before
export HOME=  # unset in container
$ codewhale
// after
export HOME=/home/user
$ codewhale
Defensive patterns

Strategy: fallback

Validate before calling

if (!process.env.HOME || !fs.existsSync(process.env.HOME)) {
  console.warn('no home directory; skipping startup-default persistence');
}

Try / catch

match try_persist_route_as_startup_default(provider, id, model) {
    Ok(_) => {}
    Err(e) => log::warn!("persist startup default skipped: {e}"),
}

Prevention

When it happens

Trigger: Selecting a provider/model in the TUI and triggering persist-as-startup-default while `home_config_path()` returns None — typically no resolvable HOME directory or a platform where the config dir cannot be determined.

Common situations: Running in a container/CI with HOME unset or set to a non-writable path; sandboxed environment without a home directory; unusual XDG_CONFIG_HOME setups.

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

Appendix: source

Thrown at crates/tui/src/tui/app.rs:1452

fn persist_route_as_startup_default(
    provider: ApiProvider,
    provider_identity: &str,
    model: &str,
) -> String {
    let route = format!("{provider_identity}/{model}");
    match try_persist_route_as_startup_default(provider, provider_identity, model) {
        Ok(()) => format!("Remembered {route} as the startup default (config.toml)."),
        Err(err) => format!("Save failed: {err}"),
    }
}

fn try_persist_route_as_startup_default(
    provider: ApiProvider,
    provider_identity: &str,
    model: &str,
) -> anyhow::Result<()> {
    let path = crate::config::home_config_path()
        .ok_or_else(|| anyhow::anyhow!("Cannot resolve the user-global model configuration."))?;
    crate::config_persistence::persist_provider_selection(
        Some(&path),
        provider,
        provider_identity,
        Some(model),
    )
    .map(|_| ())
}

pub struct App {
    pub mode: AppMode,
    /// Registered hotbar actions available for future slot config/render layers.
    pub hotbar_actions: HotbarActionRegistry,
    /// Composer sub-state (input, cursor, history, menus).
    pub composer: ComposerState,
    /// Viewport sub-state (scroll, cache, selection).
    pub viewport: ViewportState,
    /// Ocean work-surface state. Kept separate from transcript/sidebar state

View on GitHub (pinned to 73e0f67d83)