thedotmack/claude-mem · error · ChromaUnavailableError
Unable to acquire Chroma writer lock at ${lockPath}: ${error
Error message
Unable to acquire Chroma writer lock at ${lockPath}: ${error instanceof Error ? error.message : String(error)} What it means
To prevent two processes writing the same local Chroma data dir simultaneously (SQLite-like corruption risk), acquireChromaWriterLock() atomically creates a .claude-mem-chroma-writer.lock via fs.writeFileSync flag 'wx'. If writeFileSync throws anything OTHER than EEXIST (e.g. EACCES, ENOSPC, ENOENT dir missing, EROFS), it records health and throws ChromaUnavailableError with the underlying message. EEXIST is handled separately by inspecting the existing lock.
Source
Thrown at src/services/sync/ChromaMcpManager.ts:418
acquiredAt: new Date().toISOString(),
startToken: captureProcessStartToken(process.pid),
};
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
fs.writeFileSync(lockPath, JSON.stringify(payload, null, 2), {
encoding: 'utf-8',
flag: 'wx',
});
this.chromaWriterLock = { path: lockPath, dataDir: normalizedDataDir, ownerId: this.chromaWriterOwnerId };
logger.debug('CHROMA_MCP', 'Acquired Chroma writer lock', { lockPath, dataDir: normalizedDataDir });
return;
} catch (error) {
const errno = error instanceof Error ? (error as NodeJS.ErrnoException).code : undefined;
if (errno !== 'EEXIST') {
const message = `Unable to acquire Chroma writer lock at ${lockPath}: ${error instanceof Error ? error.message : String(error)}`;
recordChromaVectorSearchUnavailable(message);
throw new ChromaUnavailableError(message, error instanceof Error ? error : undefined);
}
const existing = ChromaMcpManager.readChromaWriterLock(lockPath);
if (!existing) {
const message = `Chroma writer lock at ${lockPath} is unreadable; refusing to start a second writer`;
recordChromaVectorSearchUnavailable(message);
throw new ChromaUnavailableError(message);
}
if (existing.pid === process.pid && existing.ownerId === this.chromaWriterOwnerId) {
this.chromaWriterLock = { path: lockPath, dataDir: normalizedDataDir, ownerId: this.chromaWriterOwnerId };
return;
}
if (!ChromaMcpManager.isChromaWriterLockLive(existing)) {
try {
fs.rmSync(lockPath, { force: true });
logger.info('CHROMA_MCP', 'Removed stale Chroma writer lock', {View on GitHub (pinned to d768ba3643)
Solutions
- Check the underlying message/errno in the error: fix the filesystem permission or space issue on the Chroma data dir.
- Ensure the user running the worker owns/can write the local Chroma data dir.
- Free disk space if ENOSPC; remount read-write if EROFS; relax MAC policy if it blocks the write.
- Retry the operation once the filesystem issue is resolved.
Example fix
# before ls -la ~/.claude-mem/chroma/ # owned by root, worker runs as appuser # acquireChromaWriterLock -> EACCES -> throws # after sudo chown -R appuser:appuser ~/.claude-mem/chroma # restart worker
Defensive patterns
Strategy: try-catch
Validate before calling
import { access, constants } from 'fs/promises';
import path from 'path';
async function canWriteLock(dataDir: string): Promise<boolean> {
try {
await access(path.dirname(dataDir), constants.W_OK);
return true;
} catch { return false; }
} Type guard
import { ChromaUnavailableError } from '../worker/search/errors.js';
function isWriterLockAcquireFailure(e: unknown): boolean {
return e instanceof ChromaUnavailableError && /Unable to acquire Chroma writer lock/i.test(e.message);
} Try / catch
try {
await chromaManager.search(query);
} catch (e) {
if (e instanceof ChromaUnavailableError && /Unable to acquire Chroma writer lock/i.test(e.message)) {
// Filesystem-level issue (perms/space). Surface actionable guidance, degrade to FTS.
logger.error('CHROMA', e.message, {}, e);
return await ftsSearch(query);
}
throw e;
} Prevention
- Run the worker as a user that owns/can write the Chroma data dir.
- Keep the data dir on a writable, non-read-only filesystem with free space.
- Monitor disk usage to avoid ENOSPC during embedding writes.
When it happens
Trigger: The atomic lock create fails with a non-EEXIST errno: no write permission (EACCES) on the data dir, read-only filesystem (EROFS), disk full (ENOSPC), the data dir was deleted between mkdirSync and the write (ENOENT), or a path/encoding error.
Common situations: Data dir on a read-only mount or owned by another user; disk full; SELinux/AppArmor denying writes; the chroma data dir is on a network FS that rejects exclusive create; a prior crash left filesystem in a bad state.
Related errors
- Unable to remove stale Chroma writer lock at ${lockPath}: ${
- Chroma writer lock at ${lockPath} is unreadable; refusing to
- uvx executable not found for chroma-mcp (${uvxSpawnCommand})
- Chroma data dir ${normalizedDataDir} is already owned by PID
- Unable to acquire Chroma writer lock at ${lockPath} after re
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/f2ea80451033c1b8.
Report an issue: GitHub.