{"record":{"id":"57c81ff2ec5123b1","repo":"affaan-m/ECC","slug":"git-worktree-list-porcelain-failed-stderr","errorCode":null,"errorMessage":"git worktree list --porcelain failed: {stderr}","messagePattern":"git worktree list --porcelain failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/worktree/mod.rs","lineNumber":1581,"sourceCode":"        .arg(repo_root)\n        .args([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"])\n        .output()\n        .context(\"Failed to get current branch\")?;\n\n    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())\n}\n\nfn base_checkout_path(worktree: &WorktreeInfo) -> Result<PathBuf> {\n    let output = Command::new(\"git\")\n        .arg(\"-C\")\n        .arg(&worktree.path)\n        .args([\"worktree\", \"list\", \"--porcelain\"])\n        .output()\n        .context(\"Failed to resolve git worktree list\")?;\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        anyhow::bail!(\"git worktree list --porcelain failed: {stderr}\");\n    }\n\n    let target_branch = format!(\"refs/heads/{}\", worktree.base_branch);\n    let mut current_path: Option<PathBuf> = None;\n    let mut current_branch: Option<String> = None;\n    let mut fallback: Option<PathBuf> = None;\n\n    for line in String::from_utf8_lossy(&output.stdout).lines() {\n        if line.is_empty() {\n            if let Some(path) = current_path.take() {\n                if fallback.is_none() && path != worktree.path {\n                    fallback = Some(path.clone());\n                }\n                if current_branch.as_deref() == Some(target_branch.as_str())\n                    && path != worktree.path\n                {\n                    return Ok(path);\n                }","sourceCodeStart":1563,"sourceCodeEnd":1599,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L1563-L1599","documentation":"Thrown by base_checkout_path at ecc2/src/worktree/mod.rs:1581 when `git -C <worktree.path> worktree list --porcelain` exits non-zero. base_checkout_path parses that porcelain output to find which checkout owns refs/heads/<base_branch> (the merge/rebase target). It is called by merge_into_base, rebase_onto_base, and branch_head_oid, so this error can surface from any of them. Failure means git itself refused to enumerate worktrees — usually because the worktree path is no longer registered or git metadata is corrupt.","triggerScenarios":"The worktree was pruned (git worktree prune ran, or the user manually deleted it) leaving WorktreeInfo.path dangling; the .git file in the worktree points to a back-link that no longer exists; filesystem-level removal of <worktree_path>/.git; running inside a directory that looks like a worktree but is actually a standalone clone; git version too old to support `worktree list --porcelain`.","commonSituations":"Session restart after a reboot where another process pruned worktrees; dev manually rm -rf'd a worktree dir without `git worktree remove`; storage cleanup tools that scrub hidden .git files; very old git (<2.7) without porcelain format; the worktree lives on an unmounted or permission-restricted volume.","solutions":["Check the worktree is still registered: `git -C <worktree_path> worktree list` — if missing, run `git -C <main_repo> worktree repair <worktree_path>` or recreate the worktree.","If the worktree was deleted intentionally, prune and recreate: `git -C <main_repo> worktree prune && git -C <main_repo> worktree add <path> <branch>`.","Verify the .git back-link inside the worktree is intact: `<worktree_path>/.git` should be a file pointing at `<main_repo>/.git/worktrees/<id>`.","Upgrade git to ≥2.7 if porcelain output is unsupported."],"exampleFix":"// before\nlet repo_root = base_checkout_path(&worktree)?;\n\n// after: repair the worktree registration if porcelain fails\nlet repo_root = match base_checkout_path(&worktree) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"worktree list --porcelain\") => {\n        Command::new(\"git\").arg(\"-C\").arg(&worktree.path)\n            .args([\"worktree\", \"repair\"]).status()?;\n        base_checkout_path(&worktree)?\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"validation","validationCode":"fn worktree_registered(worktree_path: &Path) -> Result<bool> {\n    let out = Command::new(\"git\").arg(\"-C\").arg(worktree_path)\n        .args([\"rev-parse\", \"--is-inside-worktree\"]).output()?;\n    Ok(out.status.success()\n        && String::from_utf8_lossy(&out.stdout).trim() == \"true\")\n}\nif !worktree_registered(&worktree.path)? {\n    Command::new(\"git\").arg(\"-C\").arg(&worktree.path)\n        .args([\"worktree\", \"repair\"]).status()?;\n}\nlet repo_root = base_checkout_path(&worktree)?;","typeGuard":"fn gitfile_intact(worktree_path: &Path) -> bool {\n    let gitfile = worktree_path.join(\".git\");\n    gitfile.is_file()  // linked worktrees use a .git file, not a directory\n}","tryCatchPattern":"match base_checkout_path(&worktree) {\n    Ok(p) => Ok(p),\n    Err(e) if e.to_string().starts_with(\"git worktree list --porcelain failed\") => {\n        Command::new(\"git\").arg(\"-C\").arg(&worktree.path)\n            .args([\"worktree\", \"repair\"]).status()?;\n        base_checkout_path(&worktree)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Never delete a worktree directory with rm -rf; use `git worktree remove`.","Run `git worktree prune` on a schedule so dangling registrations are cleaned deterministically, not mid-call.","Validate the .git back-link file at session start before trusting WorktreeInfo.path.","Pin git >= 2.7 for porcelain output support."],"tags":["git","worktree","porcelain","metadata-corruption","subprocess-failure"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}