gitbutlerapp/gitbutler · error

Could not determine home directory

Error message

Could not determine home directory

What it means

Raised in `collect_skill_installs` (crates/but/src/command/agent/plan.rs:271) when a skill install scope includes the global location (`Scope::Global` or `Scope::Both`) but `but_path::home_dir()` returns `None`, so the global base directory cannot be resolved.

Solutions

  1. Set the HOME environment variable to a writable directory before running the command
  2. On Windows ensure USERPROFILE is set; on systemd services set HOME=/root or the service user's home
  3. Use a repository-only scope (avoid Global/Both) if a home directory is not needed
  4. In containers, run as a user with a defined home (`useradd -m`) or export HOME in the entrypoint

Example fix

// before
but agent plan --scope both   # fails if HOME unset
// after
export HOME=/home/user
but agent plan --scope both
Defensive patterns

Strategy: validation

Validate before calling

if std::env::var_os("HOME").is_none() && std::env::var_os("USERPROFILE").is_none() {
    return Err("set HOME (or USERPROFILE on Windows) before running skill install commands");
}

Try / catch

match plan::collect_skill_installs(repo.as_ref(), scope) {
    Err(e) if e.to_string().contains("Could not determine home directory") => Err("set HOME and retry"),
    other => other,
}

Prevention

When it happens

Trigger: Running `but agent plan` (or related skill-install commands) with a global scope on a system where the HOME environment variable is unset and no platform home-directory API succeeds.

Common situations: Running in a stripped container/CI environment without HOME set; running as a system service with no user context; Windows deployments missing USERPROFILE; minimal Docker images.

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 gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/1f8e8f1e74dedba8. Report an issue: GitHub.

Appendix: source

Thrown at crates/but/src/command/agent/plan.rs:271

}

#[derive(Debug, Clone)]
pub(super) struct InstructionWritePlan {
    pub(super) path: PathBuf,
    pub(super) agents: Vec<AgentTarget>,
}

pub(super) fn collect_skill_installs(
    agents: &[AgentTarget],
    scope: Scope,
    repo: Option<&RepoInfo>,
) -> Result<Vec<SkillInstallPlan>> {
    // Resolve each concrete install location (a single-location scope) to its
    // base directory once, expanding `Both` into global + repository.
    let mut locations: Vec<(Scope, PathBuf)> = Vec::new();
    if matches!(scope, Scope::Global | Scope::Both) {
        let home = but_path::home_dir()
            .ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
        locations.push((Scope::Global, home));
    }
    if matches!(scope, Scope::Repository | Scope::Both) {
        let root = repo
            .map(|repo| repo.root.clone())
            .context("Repository skill install requested outside a repository")?;
        locations.push((Scope::Repository, root));
    }

    let mut installs = Vec::new();
    for agent in agents {
        for (location, base_dir) in &locations {
            if let Some(components) = agent.skill_path_components(*location) {
                installs.push(SkillInstallPlan {
                    agent: *agent,
                    path: join_components(base_dir, components),
                });
            }

View on GitHub (pinned to 58e5313667)