{"record":{"id":"9755e08116195120","repo":"stablyai/orca","slug":"failed-to-delete-worktree-at-canonicalworktreepa","errorCode":null,"errorMessage":"Failed to delete worktree at ${canonicalWorktreePath}.","messagePattern":"Failed to delete worktree at (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/worktrees.ts","lineNumber":2638,"sourceCode":"              preservedBranchCleanupByScope.delete(\n                preservedBranchCleanupScopeKey({\n                  worktreeId: args.worktreeId,\n                  hostId: removalHostId\n                })\n              )\n              notifyWorktreesChanged(mainWindow, repoId)\n              return {}\n            }\n            throw new Error(`Refusing to delete unregistered worktree path: ${worktreePath}`)\n          }\n          const canonicalWorktreePath = registeredWorktree.path\n          const deleteBranch = removedMeta?.preserveBranchOnDelete !== true\n\n          // Why: a Git lock must block before archive hooks or linked-path cleanup mutate the workspace; dirty-file force is separate.\n          try {\n            assertWorktreeUnlockedForRemoval(registeredWorktree)\n          } catch (error) {\n            throw new Error(\n              formatWorktreeRemovalError(error, canonicalWorktreePath, args.force ?? false)\n            )\n          }\n\n          // Why: a prior forced Windows recovery can delete the dir but leave a stale Git registration; verify before clearing metadata.\n          if (\n            !repo.connectionId &&\n            args.force === true &&\n            process.platform === 'win32' &&\n            (isWindowsAbsolutePathLike(canonicalWorktreePath) ||\n              !!localWorktreeGitOptions.wslDistro) &&\n            removedMeta &&\n            (await isAlreadyRemovedWorktreePath(\n              repo,\n              canonicalWorktreePath,\n              localWorktreeGitOptions\n            ))\n          ) {","sourceCodeStart":2620,"sourceCodeEnd":2656,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/worktrees.ts#L2620-L2656","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure no other Git operation is running in that worktree, then retry removal.","If a stale lockfile remains after a crash, remove it on the host and retry.","Retry with force only after confirming the lock is genuinely stale, not a live operation."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isGitLockRemovalError(e: unknown): boolean {\n  return e instanceof Error && /lock/i.test(e.message)\n}","tryCatchPattern":"try {\n  await invoke('worktrees:remove', { worktreeId, force: false })\n} catch (e) {\n  if (isGitLockRemovalError(e)) {\n    // Wait for the other Git op / remove stale lockfile, then retry once.\n    await invoke('worktrees:remove', { worktreeId, force: false })\n  } else throw e\n}","preventionTips":["Ensure no other Git operation is running in the worktree before removing.","Clear stale lockfiles left by crashed Git processes.","Don't force past a lock unless it's confirmed stale."],"tags":["worktree-remove","git-lock","safety"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}