paperclipai/paperclip · error · WorkspaceValidationFailure
git_worktree_provider_ref_mismatch
git_worktree_provider_ref_mismatch
Error message
Issue ${issue.identifier ?? issue.id} expected git worktree "${input.persistedExecutionWorkspace.providerRef}" but adapter cwd resolved to "${effectiveCwd}". What it means
A git-worktree-based execution workspace was expected (providerRef names the registered worktree), but the adapter's resolved cwd points somewhere else. This mismatch guard fires during heartbeat pre-flight to prevent runs that would execute outside the persisted worktree.
Solutions
- Restore or recreate the git worktree so the adapter cwd matches the persisted provider ref.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at server/src/services/heartbeat.ts:2134 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/5a98f5b05018a268.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/heartbeat.ts:2549
// Preserve the closed failure code without copying subprocess output or
// credentials into the durable run. Setup recovery needs the actual cause.
if (isWorkspaceGitScanError(error)) throw new WorkspaceGitScanError(error.code, message);
throw new Error(message);
}
try {
await fs.rename(cloneTmpDir, cwd);
} catch (renameError) {
await fs
.rm(cloneTmpDir, { recursive: true, force: true })
.catch(() => undefined);
// The target appearing between the emptiness check and the rename means another
// materialization won the race; adopt its checkout instead of failing the run.
if (await hasAdoptableGitDir()) {
return { cwd, warning: null };
}
const reason =
renameError instanceof Error ? renameError.message : String(renameError);
throw new Error(
`Failed to move managed checkout into place at "${cwd}": ${reason}`,
);
}
return { cwd, warning: null };
}
/** Keep every distinct project repository inside the task's writable/synced root. */
export async function prepareProjectRepositoryWorkspaces(input: {
cwd: string;
anchorRepoUrl: string | null;
workspaces: Array<Pick<typeof projectWorkspaces.$inferSelect, "id" | "repoUrl" | "repoRef"> & { cwd?: string | null }>;
resolveGitAuth?: GitRemoteAuthProvider | null;
}): Promise<Array<{ workspaceId: string; cwd: string; repoUrl: string; repoRef: string | null }>> {
const identity = (url: string) => url.trim().replace(/\.git\/?$/, "").replace(/\/$/, "");
const seen = new Set(input.anchorRepoUrl ? [identity(input.anchorRepoUrl)] : []);
const selected = input.workspaces.filter((workspace) => {
if (!workspace.repoUrl || seen.has(identity(workspace.repoUrl))) return false;View on GitHub (pinned to 3f1d897a7c)