UAT: GitWorktreeSandbox.create() fails with unhelpful error when repository is in detached HEAD state — no user-facing guidance #5483

Open
opened 2026-04-09 06:59:12 +00:00 by HAL9000 · 1 comment
Owner

Bug Report

Feature Area: git-worktree-sandbox — worktree creation failure handling
Severity: Priority/Backlog — edge case that produces an unhelpful error message

What Was Tested

Code-level analysis of GitWorktreeSandbox.create() in src/cleveragents/infrastructure/sandbox/git_worktree.py against the spec requirement for worktree creation failure handling.

Expected Behavior (from spec)

When worktree creation fails, the error should:

  1. Transition the plan to errored state
  2. Provide a clear, actionable error message explaining why the sandbox could not be created

Actual Behavior

GitWorktreeSandbox.create() (lines 211–217) reads the current branch name:

result = _run_git(
    ["rev-parse", "--abbrev-ref", "HEAD"],
    cwd=self._original_path,
    timeout=self._git_timeout,
)
self._original_branch = result.stdout.strip()

When the repository is in a detached HEAD state (e.g., after git checkout <commit-hash> or in CI environments that checkout a specific commit), git rev-parse --abbrev-ref HEAD returns "HEAD" (not a branch name).

The worktree is then created with HEAD as the starting point, which works. However, when commit() is called later, it tries to merge the sandbox branch back into "HEAD" — but "HEAD" is not a branch, so the merge will fail with a confusing error.

Additionally, GitWorktreeSandbox.create() (lines 228–229) creates the branch name as:

safe_plan_id = _sanitise_branch_name(plan_id)
self._branch_name = f"cleveragents/plan-{safe_plan_id}"

If a branch with this name already exists (e.g., from a previous failed run of the same plan), git worktree add -b <branch> will fail with:

fatal: A branch named 'cleveragents/plan-<id>' already exists.

This is caught as SandboxCreationError but the error message is:

Failed to create git worktree for resource <id>: fatal: A branch named 'cleveragents/plan-<id>' already exists.

There is no automatic cleanup of the stale branch, and no guidance on how to resolve it.

Code Locations

  • Branch name reading: src/cleveragents/infrastructure/sandbox/git_worktree.py, create() (lines 211–217)
  • Branch creation: src/cleveragents/infrastructure/sandbox/git_worktree.py, create() (lines 236–248)
  • Error handling: src/cleveragents/infrastructure/sandbox/git_worktree.py, lines 250–261

Specific Failure Scenarios

  1. Detached HEAD: Repository checked out at a specific commit (common in CI). git rev-parse --abbrev-ref HEAD returns "HEAD". The worktree is created but commit() will fail when trying to merge back.

  2. Stale branch from previous run: If a previous plan execution was interrupted before cleanup, the branch cleveragents/plan-<id> may still exist. git worktree add -b <branch> fails with "branch already exists".

  3. Insufficient disk space: tempfile.mkdtemp() may succeed but git worktree add may fail if the target filesystem is full. The error message is a raw git error without context.

  4. Git not installed: _run_git() raises FileNotFoundError which is NOT caught by the subprocess.CalledProcessError handler — it propagates as an unhandled exception.

Impact

  • CI environments using detached HEAD checkouts will fail to create sandboxes
  • Interrupted plan executions leave stale branches that prevent re-running the same plan
  • FileNotFoundError when git is not installed is not caught and produces an unhandled exception traceback

Fix Required

  1. Detached HEAD detection: After reading self._original_branch, check if it equals "HEAD" and raise SandboxCreationError with a clear message: "Cannot create sandbox: repository is in detached HEAD state. Please checkout a branch first."

  2. Stale branch cleanup: Before creating the worktree, check if the branch already exists and delete it if it has no associated worktree: git branch -D cleveragents/plan-<id> if git worktree list doesn't show it.

  3. FileNotFoundError handling: Add except FileNotFoundError to catch the case where git is not installed, and raise SandboxCreationError("git is not installed or not on PATH").


Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: uat-tester

## Bug Report **Feature Area**: git-worktree-sandbox — worktree creation failure handling **Severity**: Priority/Backlog — edge case that produces an unhelpful error message ## What Was Tested Code-level analysis of `GitWorktreeSandbox.create()` in `src/cleveragents/infrastructure/sandbox/git_worktree.py` against the spec requirement for worktree creation failure handling. ## Expected Behavior (from spec) When worktree creation fails, the error should: 1. Transition the plan to `errored` state 2. Provide a clear, actionable error message explaining why the sandbox could not be created ## Actual Behavior `GitWorktreeSandbox.create()` (lines 211–217) reads the current branch name: ```python result = _run_git( ["rev-parse", "--abbrev-ref", "HEAD"], cwd=self._original_path, timeout=self._git_timeout, ) self._original_branch = result.stdout.strip() ``` When the repository is in a **detached HEAD state** (e.g., after `git checkout <commit-hash>` or in CI environments that checkout a specific commit), `git rev-parse --abbrev-ref HEAD` returns `"HEAD"` (not a branch name). The worktree is then created with `HEAD` as the starting point, which works. However, when `commit()` is called later, it tries to merge the sandbox branch back into `"HEAD"` — but `"HEAD"` is not a branch, so the merge will fail with a confusing error. Additionally, `GitWorktreeSandbox.create()` (lines 228–229) creates the branch name as: ```python safe_plan_id = _sanitise_branch_name(plan_id) self._branch_name = f"cleveragents/plan-{safe_plan_id}" ``` If a branch with this name already exists (e.g., from a previous failed run of the same plan), `git worktree add -b <branch>` will fail with: ``` fatal: A branch named 'cleveragents/plan-<id>' already exists. ``` This is caught as `SandboxCreationError` but the error message is: ``` Failed to create git worktree for resource <id>: fatal: A branch named 'cleveragents/plan-<id>' already exists. ``` There is no automatic cleanup of the stale branch, and no guidance on how to resolve it. ## Code Locations - **Branch name reading**: `src/cleveragents/infrastructure/sandbox/git_worktree.py`, `create()` (lines 211–217) - **Branch creation**: `src/cleveragents/infrastructure/sandbox/git_worktree.py`, `create()` (lines 236–248) - **Error handling**: `src/cleveragents/infrastructure/sandbox/git_worktree.py`, lines 250–261 ## Specific Failure Scenarios 1. **Detached HEAD**: Repository checked out at a specific commit (common in CI). `git rev-parse --abbrev-ref HEAD` returns `"HEAD"`. The worktree is created but `commit()` will fail when trying to merge back. 2. **Stale branch from previous run**: If a previous plan execution was interrupted before cleanup, the branch `cleveragents/plan-<id>` may still exist. `git worktree add -b <branch>` fails with "branch already exists". 3. **Insufficient disk space**: `tempfile.mkdtemp()` may succeed but `git worktree add` may fail if the target filesystem is full. The error message is a raw git error without context. 4. **Git not installed**: `_run_git()` raises `FileNotFoundError` which is NOT caught by the `subprocess.CalledProcessError` handler — it propagates as an unhandled exception. ## Impact - CI environments using detached HEAD checkouts will fail to create sandboxes - Interrupted plan executions leave stale branches that prevent re-running the same plan - `FileNotFoundError` when git is not installed is not caught and produces an unhandled exception traceback ## Fix Required 1. **Detached HEAD detection**: After reading `self._original_branch`, check if it equals `"HEAD"` and raise `SandboxCreationError` with a clear message: "Cannot create sandbox: repository is in detached HEAD state. Please checkout a branch first." 2. **Stale branch cleanup**: Before creating the worktree, check if the branch already exists and delete it if it has no associated worktree: `git branch -D cleveragents/plan-<id>` if `git worktree list` doesn't show it. 3. **FileNotFoundError handling**: Add `except FileNotFoundError` to catch the case where git is not installed, and raise `SandboxCreationError("git is not installed or not on PATH")`. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
Author
Owner

Label compliance fix applied:

  • Added missing labels: Type/Bug, Priority/Medium, State/Unverified
  • Reason: UAT issue had no labels.

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: backlog-groomer

Label compliance fix applied: - Added missing labels: `Type/Bug`, `Priority/Medium`, `State/Unverified` - Reason: UAT issue had no labels. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: backlog-groomer
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#5483
No description provided.