thedotmack/claude-mem · error · ChromaUnavailableError
Unable to acquire Chroma writer lock at
Error message
Unable to acquire Chroma writer lock at ${lockPath}: ${error instanceof Error ? error.message : String(error)} What it means
acquireChromaWriterLock creates a lockfile (O_EXCL-style) to ensure only one chroma-mcp writer runs. If creation fails with an errno other than EEXIST (e.g. EACCES, ENOSPC, EPERM), the lock cannot be managed at all, so it records unavailability and throws ChromaUnavailableError with the lock path and cause.
Solutions
- Check the errno/cause in the message; verify the lock file's parent directory exists and is writable by the process user.
- Fix permissions (chown/chmod) or point the data/lock directory to a writable location via settings.
- Free disk space / quota if ENOSPC.
- If running in a container, mount the data directory as a writable volume.
Example fix
// before (container) # no volume -> read-only lock dir // after docker run -v claude-mem-data:/root/.claude-mem image
Defensive patterns
Strategy: try-catch
Validate before calling
import fs from 'fs';
const lockDir = path.dirname(lockPath);
fs.mkdirSync(lockDir, { recursive: true });
fs.accessSync(lockDir, fs.constants.W_OK); // throws early if not writable Try / catch
try {
await manager.ensureConnected();
} catch (e) {
if (e instanceof ChromaUnavailableError && e.message.includes('Unable to acquire Chroma writer lock')) {
logger.error('Fix lock dir permissions/disk space:', { cause: e.cause ?? e.message });
disableVectorSearchLocally();
} else throw e;
} Prevention
- Run the app as a user with write access to the data/lock directory.
- Mount data directories as writable volumes in containers.
- Monitor disk space/quota on the partition holding ~/.claude-mem.
- Check the lock parent directory exists and is writable at startup.
When it happens
Trigger: connectInternal attempting to acquire the writer lock when the lock directory is missing or read-only, the filesystem denies writes (permissions, read-only mount, sandbox), the disk is full, or a path-level error other than 'file already exists' occurs.
Common situations: Running under a restricted user or container without write access to the lock path (often under ~/.claude-mem or the data dir); HOME misconfigured so the lock path is invalid; read-only rootfs in Docker; disk quota exhausted.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Unable to remove unreadable Chroma writer lock at
- [ide-detection] Failed to read VS Code extensions directory:
- installPluginDependencies: no package.json at
- [uninstall] Could not read
- [uninstall] Could not read
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/f2ea80451033c1b8.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sync/ChromaMcpManager.ts:485
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) {
// Without a readable owner the liveness reaper below can never run,
// so vector sync would stay dead until someone deletes the file (#3916).
// Treat an unreadable lock that is past the write grace period as stale.
if (ChromaMcpManager.isChromaWriterLockAbandoned(lockPath)) {
try {
fs.rmSync(lockPath, { force: true });
logger.info('CHROMA_MCP', 'Removed unreadable Chroma writer lock', { lockPath });
continue;
} catch (removeError) {
const message = `Unable to remove unreadable Chroma writer lock at ${lockPath}: ${removeError instanceof Error ? removeError.message : String(removeError)}`;
recordChromaVectorSearchUnavailable(message);
throw new ChromaUnavailableError(message, removeError instanceof Error ? removeError : undefined);
}
}View on GitHub (pinned to d8bc9755e7)