thedotmack/claude-mem · error · ChromaUnavailableError

uvx executable not found for chroma-mcp

Error message

uvx executable not found for chroma-mcp (${uvxSpawnCommand})

What it means

During connectInternal, the manager preflights the uvx command (resolved via resolveUvxCommand, typically 'uvx' or an absolute path). If isUvxAvailable reports the executable cannot be run on the current platform/env, it records vector-search unavailability and throws ChromaUnavailableError naming the resolved command.

Solutions

  1. Install uv (e.g. curl -LsSf https://astral.sh/uv/install.sh | sh) so uvx is on PATH.
  2. Ensure the process's PATH includes the uv install dir (~/.local/bin) or set the resolved uvx path in settings.
  3. Verify with `which uvx` in the same environment the app runs in (daemons often have a different PATH).
  4. If vector search is not needed, disable the Chroma/remote-sync feature so connection is never attempted.

Example fix

// before (daemon unit)
ExecStart=/usr/bin/node server.js
// after
Environment="PATH=/home/user/.local/bin:/usr/bin:/bin"
ExecStart=/usr/bin/node server.js
Defensive patterns

Strategy: fallback

Validate before calling

import { execFileSync } from 'child_process';
function uvxAvailable(): boolean {
  try { execFileSync('uvx', ['--version'], { stdio: 'ignore' }); return true; }
  catch { return false; }
}
if (!uvxAvailable()) skipVectorSync();

Try / catch

try {
  await manager.ensureConnected();
} catch (e) {
  if (e instanceof ChromaUnavailableError && e.message.includes('uvx executable not found')) {
    logger.error('Install uv/uvx or disable Chroma vector search');
    disableVectorSearchLocally();
  } else throw e;
}

Prevention

When it happens

Trigger: Starting a chroma-mcp connection when uvx (from the uv toolchain) is not installed, is not on PATH, the resolved path no longer exists, or the preflight environment (custom PATH/env) hides it.

Common situations: Fresh machines or CI containers without uv installed; Claude-mem's auto-installer skipped or failed; running the app under a daemon/systemd unit whose PATH differs from the interactive shell; CLAUDE_MEM_CHROMA_MODE pointing at remote/local variants that still need uvx.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/7336acecd21aa8d0. Report an issue: GitHub.

Appendix: source

Thrown at src/services/sync/ChromaMcpManager.ts:230

    this.assertConnectionNotCancelled(connectionGeneration);

    const localChromaDataDir = this.getLocalPersistentChromaDataDir();
    const commandArgs = this.buildCommandArgs(localChromaDataDir);
    const uvxPreflightEnv = ChromaMcpManager.getUvxPreflightEnv();
    getSupervisor().assertCanSpawn('chroma mcp');

    // Spawn uvx DIRECTLY (no `cmd.exe` shell wrapper). On Windows, routing through
    // cmd.exe makes it parse the `>`/`<` in the dep-override specs as shell
    // redirection before uvx sees them; a shell-less spawn passes them literally.
    // resolveUvxCommand returns the absolute uvx.exe path on Windows (Node won't
    // PATHEXT-resolve a bare `uvx`) and bare `uvx` elsewhere (#2696).
    const uvxSpawnCommand = ChromaMcpManager.resolveUvxCommand();
    const uvxSpawnArgs = commandArgs;

    if (!ChromaMcpManager.isUvxAvailable(uvxSpawnCommand, uvxPreflightEnv, process.platform)) {
      const message = `uvx executable not found for chroma-mcp (${uvxSpawnCommand})`;
      recordUvxVectorSearchUnavailable(message);
      throw new ChromaUnavailableError(message);
    }

    const spawnEnvironment = this.getSpawnEnv(uvxPreflightEnv);

    await this.prewarmChromaMcp(uvxSpawnCommand, uvxSpawnArgs, spawnEnvironment, connectionGeneration);
    this.assertConnectionNotCancelled(connectionGeneration);

    clearDependencyStatus('uvx');

    logger.info('CHROMA_MCP', 'Connecting to chroma-mcp via MCP stdio', {
      command: uvxSpawnCommand,
      args: uvxSpawnArgs.join(' ')
    });

    try {
      if (localChromaDataDir) {
        this.acquireChromaWriterLock(localChromaDataDir);
      }

View on GitHub (pinned to d8bc9755e7)