{"record":{"id":"0822c61595da4f9d","repo":"santifer/career-ops","slug":"cannot-verify-tracker-lock-ownership-at-lockdir","errorCode":null,"errorMessage":"Cannot verify tracker lock ownership at ${lockDir}","messagePattern":"Cannot verify tracker lock ownership at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"tracker-utils.mjs","lineNumber":385,"sourceCode":"              currentDir = statSync(lockDir);\n            } catch (err) {\n              if (err?.code === 'ENOENT') {\n                released = true;\n                return;\n              }\n              throw err;\n            }\n            if (!sameLockDirectory(verifiedDir, currentDir)) {\n              released = true;\n              return;\n            }\n            const owner = readLockOwner(lockDir);\n            if (owner && owner.token !== token) {\n              released = true;\n              return;\n            }\n            if (!owner && existsSync(join(lockDir, 'owner.json'))) {\n              throw new Error(`Cannot verify tracker lock ownership at ${lockDir}`);\n            }\n          } else {\n            let beforeRead;\n            try {\n              beforeRead = statSync(lockDir);\n            } catch (err) {\n              if (err?.code === 'ENOENT') {\n                released = true;\n                return;\n              }\n              throw err;\n            }\n            const owner = readLockOwner(lockDir);\n            if (owner?.token !== token) {\n              if (owner) released = true;\n              else throw new Error(`Cannot verify tracker lock ownership at ${lockDir}`);\n              return;\n            }","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/tracker-utils.mjs#L367-L403","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await operation();\n} catch (err) {\n  if (err.message.includes('Cannot verify tracker lock ownership')) {\n    console.error('Stale/corrupt lock detected. Removing lock dir and retrying.');\n    fs.rmSync(lockDir, { recursive: true, force: true });\n    await operation();\n  } else throw err;\n}","preventionTips":["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."],"tags":["locking","lock-ownership","tracker","concurrency","toctou"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}