jlcodes99/cockpit-tools · critical

无法获取用户目录

Error message

无法获取用户目录

What it means

get_old_codex_data_dir resolves the legacy Codex data directory via dirs::data_local_dir(), falling back to dirs::home_dir().expect("无法获取用户目录"). If both the local data dir and the home dir are unavailable it panics. It is used only by migrate_codex_data_if_needed for one-time migration.

Source

Thrown at crates/cockpit-core/src/modules/codex_account_core_provider.rs:887

    // built-in `openai` provider with this account's own base URL and auth.json API key.
    let builtin_openai_config = resolve_api_provider_config(
        provider_config.base_url.as_deref(),
        Some(CodexApiProviderMode::OpenaiBuiltin),
        None,
        None,
    )?;
    write_api_provider_to_config_toml(base_dir, &builtin_openai_config)
}

/// 旧版数据目录(~/Library/Application Support/com.antigravity.cockpit-tools/)
fn get_old_codex_data_dir() -> PathBuf {
    #[cfg(test)]
    if let Some(data_dir) = std::env::var_os("COCKPIT_TOOLS_DATA_DIR") {
        return PathBuf::from(data_dir).join("legacy-codex-data");
    }

    dirs::data_local_dir()
        .unwrap_or_else(|| dirs::home_dir().expect("无法获取用户目录"))
        .join("com.antigravity.cockpit-tools")
}

/// 将旧目录中的 codex 数据迁移到新目录(一次性,迁移成功后删除旧文件)
fn migrate_codex_data_if_needed(new_data_dir: &PathBuf) {
    #[cfg(test)]
    if std::env::var_os("COCKPIT_TOOLS_DATA_DIR").is_some() {
        // Test guards use an explicit data root; never migrate the user's legacy files.
        return;
    }

    let old_dir = get_old_codex_data_dir();
    if !old_dir.exists() {
        return;
    }

    // 迁移 codex_accounts.json
    let old_index = old_dir.join("codex_accounts.json");

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Set HOME (Unix) or USERPROFILE/LOCALAPPDATA (Windows) so dirs can resolve a path.
  2. Set COCKPIT_TOOLS_DATA_DIR (test builds) to bypass legacy-dir resolution.
  3. Skip migration when no home directory can be resolved — migration is optional one-time work.
  4. Run the app under a normal user account with a profile rather than a bare service account.

Example fix

// before
migrate_codex_data_if_needed(&data_dir); // panics without HOME

// after
if std::env::var_os("HOME").is_some()
    || std::env::var_os("USERPROFILE").is_some()
{
    migrate_codex_data_if_needed(&data_dir);
} else {
    eprintln!("no home dir; skipping legacy migration");
}
Defensive patterns

Strategy: validation

Validate before calling

fn legacy_migration_env_ok() -> bool {
    std::env::var_os("COCKPIT_TOOLS_DATA_DIR").is_some()
        || std::env::var_os("HOME").is_some()
        || std::env::var_os("USERPROFILE").is_some()
}

Try / catch

std::panic::catch_unwind(get_old_codex_data_dir).map_err(|_| anyhow::anyhow!("无法获取用户目录"))

Prevention

When it happens

Trigger: Calling migrate_codex_data_if_needed (which calls get_old_codex_data_dir) on a system where dirs::data_local_dir() and dirs::home_dir() both return None — no XDG/USERPROFILE environment and no resolvable home.

Common situations: Test/CI environments with a stripped environment (COCKPIT_TOOLS_DATA_DIR unset and no HOME); running under a service account without a profile; broken passwd/XDG configuration.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/b61978b68ddea7b7. Report an issue: GitHub.