paperclipai/paperclip · error

Refusing terminal workspace cleanup because the git…

Error message

Refusing terminal workspace cleanup because the git worktree changed after delivery was verified

What it means

Integrity-violation check in assertTerminalCleanupGitStateUnchanged: the git inspection succeeded, but the worktree's current HEAD/branch differs from the expectedHeadSha captured when delivery was verified — the workspace changed after its final state was signed off. Terminal cleanup is refused to avoid destroying unaccounted-for work.

Solutions

  1. Inspect the worktree changes made after delivery verification; restore the verified state or clean up manually.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/execution-workspaces.ts:1464 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-08-18). Data as JSON: /api/errors/5a8c106be181c4a0. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/execution-workspaces.ts:1470

        sourceIssueTerminal,
        mergedPullRequest,
        pullRequestStateUnknown,
        isMergedIntoBase: git?.isMergedIntoBase ?? null,
      }),
      sourceIssueTerminal,
      subtreeTerminal,
      cooldownAnchor,
      workspaceDirty: Boolean(git?.hasDirtyTrackedFiles || git?.hasUntrackedFiles),
      workspaceHeadSha,
    };
  }

  async function assertTerminalCleanupGitStateUnchanged(
    workspace: ExecutionWorkspaceRow,
    expectedHeadSha: string | null,
  ) {
    if (workspace.providerType !== "git_worktree") return;
    const workspacePath = readNullableString(workspace.providerRef) ?? readNullableString(workspace.cwd);
    if (!workspacePath || !expectedHeadSha) {
      throw new Error("Refusing terminal workspace cleanup because the expected git HEAD is unknown");
    }

    const [current, currentHeadSha, currentBranchName] = await Promise.all([
      inspectGitCloseReadiness(toExecutionWorkspace(workspace)),
      readGitStdout(["rev-parse", "HEAD"], workspacePath).catch(() => null),
      readGitStdout(["symbolic-ref", "--quiet", "--short", "HEAD"], workspacePath).catch(() => null),
    ]);
    if (!current.statusInspectionSucceeded) {
      throw new Error("Refusing terminal workspace cleanup because the git status could not be verified");
    }
    if (
      !current.git?.repoRoot
      || current.git.hasDirtyTrackedFiles
      || current.git.hasUntrackedFiles
      || currentHeadSha !== expectedHeadSha
      || (workspace.branchName && currentBranchName !== workspace.branchName)

View on GitHub (pinned to 3f1d897a7c)