santifer/career-ops · critical · Error
Cannot verify tracker lock ownership at ${lockDir}
Error message
Cannot verify tracker lock ownership at ${lockDir} What it means
During tracker lock release (the ownerVerified branch), the code re-reads owner.json to confirm the releasing caller still owns the lock. If readLockOwner returns null/undefined (cannot parse owner.json) BUT the file exists on disk, it throws an Error — because it cannot prove ownership either way (the file is present but unreadable/corrupt). This is a fail-safe against releasing a lock the caller may not own.
Source
Thrown at tracker-utils.mjs:385
currentDir = statSync(lockDir);
} catch (err) {
if (err?.code === 'ENOENT') {
released = true;
return;
}
throw err;
}
if (!sameLockDirectory(verifiedDir, currentDir)) {
released = true;
return;
}
const owner = readLockOwner(lockDir);
if (owner && owner.token !== token) {
released = true;
return;
}
if (!owner && existsSync(join(lockDir, 'owner.json'))) {
throw new Error(`Cannot verify tracker lock ownership at ${lockDir}`);
}
} else {
let beforeRead;
try {
beforeRead = statSync(lockDir);
} catch (err) {
if (err?.code === 'ENOENT') {
released = true;
return;
}
throw err;
}
const owner = readLockOwner(lockDir);
if (owner?.token !== token) {
if (owner) released = true;
else throw new Error(`Cannot verify tracker lock ownership at ${lockDir}`);
return;
}View on GitHub (pinned to 9b17a8ac97)
Solutions
- Remove the stale lock directory manually (locate the .lock dir near the tracker, delete it) — it will be recreated on next acquire.
- Use the force release path if available in the calling code to bypass ownership checks administratively.
- Investigate what corrupted owner.json (concurrent writers, crash) to prevent recurrence.
- Increase CAREER_OPS_TRACKER_LOCK_STALE_MS if long-held locks are being scavenged mid-operation.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await operation();
} catch (err) {
if (err.message.includes('Cannot verify tracker lock ownership')) {
console.error('Stale/corrupt lock detected. Removing lock dir and retrying.');
fs.rmSync(lockDir, { recursive: true, force: true });
await operation();
} else throw err;
} Prevention
- Ensure only one process family coordinates on a given tracker lock directory.
- Avoid external cleanup tools that delete owner.json without removing the whole lock dir.
- Investigate crashes that leave partial owner.json files; consider fsync-on-write in the lock layer.
When it happens
Trigger: owner.json exists but is corrupt/truncated (invalid JSON), or readLockOwner encounters a permission error reading it, during the release() call on a verified lock. This is a TOCTOU edge: the file was readable at acquire time but became corrupt before release.
Common situations: Concurrent processes interfering with the lock directory; a crash mid-write leaving a partial owner.json; filesystem issues; manual tampering with the lock directory's owner.json between acquire and release.
Related errors
- LOCK_TIMEOUT
- pipeline lock timeout: ${lockDir} held > ${timeoutMs}ms
- Could not claim ${count} report slot(s) after ${MAX_RETRIES}
- ROW_NOT_FOUND
- portal-health lock timeout: ${lockDir} held > ${timeoutMs}ms
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/0822c61595da4f9d.
Report an issue: GitHub.