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

  1. Check the errno/cause in the message; verify the lock file's parent directory exists and is writable by the process user.
  2. Fix permissions (chown/chmod) or point the data/lock directory to a writable location via settings.
  3. Free disk space / quota if ENOSPC.
  4. 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

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


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)