stablyai/orca · error · Error

Failed to delete worktree at ${canonicalWorktreePath}.

Error message

Failed to delete worktree at ${canonicalWorktreePath}.

What it means

Thrown when assertWorktreeUnlockedForRemoval(registeredWorktree) fails on the initial lock check before any destructive step. formatWorktreeRemovalError wraps the underlying message (Git lockfile/index.lock held by another client). A Git lock must block before archive hooks or linked-path cleanup mutate the workspace.

Source

Thrown at src/main/ipc/worktrees.ts:2638

              preservedBranchCleanupByScope.delete(
                preservedBranchCleanupScopeKey({
                  worktreeId: args.worktreeId,
                  hostId: removalHostId
                })
              )
              notifyWorktreesChanged(mainWindow, repoId)
              return {}
            }
            throw new Error(`Refusing to delete unregistered worktree path: ${worktreePath}`)
          }
          const canonicalWorktreePath = registeredWorktree.path
          const deleteBranch = removedMeta?.preserveBranchOnDelete !== true

          // Why: a Git lock must block before archive hooks or linked-path cleanup mutate the workspace; dirty-file force is separate.
          try {
            assertWorktreeUnlockedForRemoval(registeredWorktree)
          } catch (error) {
            throw new Error(
              formatWorktreeRemovalError(error, canonicalWorktreePath, args.force ?? false)
            )
          }

          // Why: a prior forced Windows recovery can delete the dir but leave a stale Git registration; verify before clearing metadata.
          if (
            !repo.connectionId &&
            args.force === true &&
            process.platform === 'win32' &&
            (isWindowsAbsolutePathLike(canonicalWorktreePath) ||
              !!localWorktreeGitOptions.wslDistro) &&
            removedMeta &&
            (await isAlreadyRemovedWorktreePath(
              repo,
              canonicalWorktreePath,
              localWorktreeGitOptions
            ))
          ) {

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Ensure no other Git operation is running in that worktree, then retry removal.
  2. If a stale lockfile remains after a crash, remove it on the host and retry.
  3. Retry with force only after confirming the lock is genuinely stale, not a live operation.
Defensive patterns

Strategy: retry

Type guard

function isGitLockRemovalError(e: unknown): boolean {
  return e instanceof Error && /lock/i.test(e.message)
}

Try / catch

try {
  await invoke('worktrees:remove', { worktreeId, force: false })
} catch (e) {
  if (isGitLockRemovalError(e)) {
    // Wait for the other Git op / remove stale lockfile, then retry once.
    await invoke('worktrees:remove', { worktreeId, force: false })
  } else throw e
}

Prevention

When it happens

Trigger: A worktrees:remove where another Git process holds the worktree's lock (index.lock, or a `git` operation in progress in that worktree) at the moment removal begins.

Common situations: An IDE, a background fetch, a running commit/rebase, or a crashed Git process left a lockfile in the worktree; SSH host has a stale lock from a dropped session.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/9755e08116195120. Report an issue: GitHub.