{"record":{"id":"1f8e8f1e74dedba8","repo":"gitbutlerapp/gitbutler","slug":"could-not-determine-home-directory","errorCode":null,"errorMessage":"Could not determine home directory","messagePattern":"Could not determine home directory","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but/src/command/agent/plan.rs","lineNumber":271,"sourceCode":"}\n\n#[derive(Debug, Clone)]\npub(super) struct InstructionWritePlan {\n    pub(super) path: PathBuf,\n    pub(super) agents: Vec<AgentTarget>,\n}\n\npub(super) fn collect_skill_installs(\n    agents: &[AgentTarget],\n    scope: Scope,\n    repo: Option<&RepoInfo>,\n) -> Result<Vec<SkillInstallPlan>> {\n    // Resolve each concrete install location (a single-location scope) to its\n    // base directory once, expanding `Both` into global + repository.\n    let mut locations: Vec<(Scope, PathBuf)> = Vec::new();\n    if matches!(scope, Scope::Global | Scope::Both) {\n        let home = but_path::home_dir()\n            .ok_or_else(|| anyhow::anyhow!(\"Could not determine home directory\"))?;\n        locations.push((Scope::Global, home));\n    }\n    if matches!(scope, Scope::Repository | Scope::Both) {\n        let root = repo\n            .map(|repo| repo.root.clone())\n            .context(\"Repository skill install requested outside a repository\")?;\n        locations.push((Scope::Repository, root));\n    }\n\n    let mut installs = Vec::new();\n    for agent in agents {\n        for (location, base_dir) in &locations {\n            if let Some(components) = agent.skill_path_components(*location) {\n                installs.push(SkillInstallPlan {\n                    agent: *agent,\n                    path: join_components(base_dir, components),\n                });\n            }","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but/src/command/agent/plan.rs#L253-L289","documentation":"collect_skill_installs resolves the base directory for global skill installs via but_path::home_dir(), which returns None only when the underlying home-directory lookup fails (it first honors E2E_TEST_APP_DATA_DIR, then delegates to dirs::home_dir()). On Unix this happens when $HOME is unset or empty; on Windows when the user profile APIs yield nothing. Without a home directory there is nowhere to place ~/.agents-style global skills, so planning fails fast rather than writing to a guessed path.","triggerScenarios":"Running an agent skill-install command with Scope::Global or Scope::Both in a shell where HOME is unset/empty (cron jobs, bare systemd units, docker containers run without env, `env -i`), or in a test harness that neither sets E2E_TEST_APP_DATA_DIR nor provides a home directory.","commonSituations":"CI containers (alpine/slim images) that strip environment variables; launchd/systemd services without Environment=HOME=; running as a UID without a passwd entry; misconfigured sudo that drops HOME (`sudo but ...` with env_reset).","solutions":["Run the command with HOME set: `HOME=$HOME but ...` in the failing context, or add `Environment=HOME=/root` / `SetEnv HOME=` to the service/cron definition.","For automation and e2e runs, set E2E_TEST_APP_DATA_DIR — home_dir() then returns <dir>/home deterministically.","If using sudo, preserve HOME (`sudo -E`) or set `env_keep+=HOME` in sudoers.","If no global install is intended, scope the install to the repository (Scope::Repository) which uses the repo root instead."],"exampleFix":"# before: cron job with no HOME\n0 * * * * but agent skill install --global my-skill\n# -> Error: Could not determine home directory\n\n# after: provide HOME explicitly\n0 * * * * HOME=/home/user but agent skill install --global my-skill","handlingStrategy":"validation","validationCode":"// Check before planning a global skill install\nmatch but_path::home_dir() {\n    Some(home) => { /* safe to install globally into {home} */ }\n    None => {\n        eprintln!(\"HOME is not set; set HOME or E2E_TEST_APP_DATA_DIR, or use --repo scope\");\n        std::process::exit(2);\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always define HOME in cron/systemd/container definitions that run the CLI.","Use E2E_TEST_APP_DATA_DIR in tests to pin a deterministic home.","Prefer repository-scoped installs in headless environments."],"tags":["environment","home-directory","skills","agents"],"backgroundTag":"missing-home-env-var","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}