paperclipai/paperclip · error · Error
Failed to integrate concurrent remote git history for ${inpu
Error message
Failed to integrate concurrent remote git history for ${input.importedHead.slice(0, 12)} after multiple retries. What it means
Thrown by integrateImportedGitHead after all 5 retry attempts fail with concurrent ref update lock errors. Each attempt calls `git update-ref` which fails with 'cannot lock ref ... expected ...', indicating another process is concurrently updating the same git ref. After exhausting retries, the integration gives up.
Source
Thrown at packages/adapter-utils/src/git-workspace-sync.ts:464
],
{
timeout: 60_000,
maxBuffer: 64 * 1024,
},
);
try {
await runLocalGit(input.localDir, ["update-ref", headRef, mergeCommit.stdout.trim(), currentHead], {
timeout: 10_000,
maxBuffer: 16 * 1024,
});
return;
} catch (error) {
if (isConcurrentRefUpdateError(error) && attempt < 4) continue;
throw error;
}
}
throw new Error(`Failed to integrate concurrent remote git history for ${input.importedHead.slice(0, 12)} after multiple retries.`);
}
export async function resetLocalGitIndexToHead(input: {
localDir: string;
checkWorkingTreeClean?: boolean;
}): Promise<void> {
try {
await runLocalGit(input.localDir, ["reset", "--quiet", "HEAD", "--", "."], {
timeout: 60_000,
maxBuffer: 1024 * 1024,
});
} catch (error) {
const detail = error && typeof error === "object"
? [
(error as { message?: unknown }).message,
(error as { stderr?: unknown }).stderr,
(error as { stdout?: unknown }).stdout,
].filter((value): value is string => typeof value === "string" && value.trim().length > 0).join("\n")View on GitHub (pinned to 67001ec6eb)
Solutions
- Serialize workspace sync operations so only one integrateImportedGitHead runs at a time per workspace.
- Remove stale git lock files (`.git/*.lock`, `.git/refs/**/*.lock`) if a previous process crashed.
- Check for concurrent agent runs targeting the same localDir and coordinate them.
- If on NFS/shared storage, move the workspace to a local filesystem to reduce lock contention.
Defensive patterns
Strategy: retry
Validate before calling
// Check for stale lock files before integrating
async function cleanStaleGitLocks(localDir: string): Promise<void> {
const glob = await import("node:fs/promises");
// Remove stale ref lock files older than 5 minutes
// (only safe when no other git process is running)
} Try / catch
try {
await integrateImportedGitHead({ localDir, importedHead });
} catch (err) {
if (err instanceof Error && err.message.includes("after multiple retries")) {
// Lock contention persisted — serialize and retry after a delay
await cleanStaleGitLocks(localDir);
await integrateImportedGitHead({ localDir, importedHead });
} else {
throw err;
}
} Prevention
- Serialize workspace sync operations with a mutex per localDir.
- Clean up stale .git lock files after crashes.
- Avoid running git gc/repack concurrently with workspace sync.
- Use a local filesystem instead of NFS for workspace repos to reduce lock contention.
When it happens
Trigger: Calling integrateImportedGitHead in a context where another concurrent process (another agent run, a parallel workspace sync, or a git gc) is locking the same ref. All 5 iterations of the for-loop hit isConcurrentRefUpdateError(error) and attempt < 4 continues, then the loop exits and this terminal throw fires.
Common situations: Multiple agent runs syncing to the same workspace simultaneously; a long-running git gc or repack holding ref locks; stale .git/refs/<ref>.lock files left by a crashed process; NFS or shared-filesystem lock contention.
Related errors
- Failed to merge concurrent remote git histories for ${curren
- Failed to compute a merged git tree for workspace restore.
- Failed to reset local git index to HEAD after workspace rest
- Failed to integrate concurrent SSH git history for ${input.i
- Another restart for instance ${instanceId} is still running.
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/1b49d5e841d0561c.
Report an issue: GitHub.