paperclipai/paperclip · error · Error
Worktree seed lock ${lockPath} is stale or malformed. Verify
Error message
Worktree seed lock ${lockPath} is stale or malformed. Verify that no seed is running, then remove the stale lock and retry. What it means
Thrown by acquireWorktreeSeedLock when the lock file exists but its content cannot be parsed into a valid owner AND the file's mtime is older than WORKTREE_SEED_LOCK_MALFORMED_STALE_MS (60s). This treats a corrupt/unrecognizable lock as stale only after the grace window, to avoid racing a live process that just hasn't finished writing.
Source
Thrown at cli/src/commands/worktree.ts:1540
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
}
const [rawOwner, lockStat] = await Promise.all([
fsPromises.readFile(lockPath, "utf8").catch(() => null),
fsPromises.stat(lockPath).catch(() => null),
]);
const currentOwner = rawOwner ? parseWorktreeSeedLockOwner(rawOwner) : null;
const malformedLockIsStale = Boolean(
lockStat && Date.now() - lockStat.mtimeMs >= WORKTREE_SEED_LOCK_MALFORMED_STALE_MS,
);
if (currentOwner && !processIsAlive(currentOwner.pid)) {
throw new Error(
`Worktree seed lock ${lockPath} belongs to exited process ${currentOwner.pid}. `
+ "Verify that no seed is running, then remove the stale lock and retry.",
);
}
if (!currentOwner && malformedLockIsStale) {
throw new Error(
`Worktree seed lock ${lockPath} is stale or malformed. `
+ "Verify that no seed is running, then remove the stale lock and retry.",
);
}
await new Promise((resolve) => setTimeout(resolve, WORKTREE_SEED_LOCK_POLL_MS));
}
}
export async function ensureWorktreeSeeded(
opts: WorktreeEnsureSeededOptions = {},
dependencies: { seedDatabase?: SeedWorktreeDatabase } = {},
): Promise<EnsureWorktreeSeededResult> {
const configPath = resolveConfigPath(opts.config);
const markers = resolveWorktreeSeedMarkerPaths(configPath);
mkdirSync(path.dirname(markers.lock), { recursive: true });
const releaseLock = await acquireWorktreeSeedLock(markers.lock);
try {
// These checks deliberately happen under the cross-process lock. A secondView on GitHub (pinned to 67001ec6eb)
Solutions
- Confirm no seed is currently running.
- Delete the malformed/stale lock file at the given path.
- Retry the seed command.
- If this recurs, check for processes or tools writing to the lock path, and filesystem sync/clock issues.
Example fix
# before: malformed lock older than 60s # after ps aux | grep paperclip rm <lockPath-from-error> paperclipai worktree reseed ...
Defensive patterns
Strategy: validation
Validate before calling
function lockIsStaleOrMalformed(lockPath: string): boolean {
const raw = fs.readFileSync(lockPath, 'utf8').catch?.(() => null);
const owner = raw ? parseWorktreeSeedLockOwner(raw) : null;
const stat = fs.statSync(lockPath);
return !owner && Date.now() - stat.mtimeMs >= WORKTREE_SEED_LOCK_MALFORMED_STALE_MS;
} Try / catch
try {
await acquireWorktreeSeedLock(lockPath);
} catch (e) {
if (/stale or malformed/.test((e as Error).message) && !anySeedRunning()) {
fs.rmSync(lockPath, { force: true }); // retry
} else throw e;
} Prevention
- Confirm no seed is running before deleting locks.
- Investigate recurring malformed locks (concurrent writers, clock skew).
- Keep the seed lock write atomic.
When it happens
Trigger: Lock file exists but is empty, partially written, or contains non-JSON/invalid JSON; more than 60 seconds have passed since its mtime; no current owner could be extracted to check liveness.
Common situations: Crash during lock write leaving a truncated file; another tool overwrote the lock with garbage; filesystem clock skew making mtime appear old; manual creation of an empty lock file.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Worktree seed lock ${lockPath} belongs to exited process ${c
- Invalid worktree seed-pending marker at ${filePath}: ${error
- Another restart for instance ${instanceId} is still running.
- Invalid worktree seed-pending marker at ${filePath}.
- Source and target Paperclip configs are the same. Pass --fro
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/a3b31f0310923c0d.
Report an issue: GitHub.