thedotmack/claude-mem · error · Error

CLAUDE_CODE_PATH is set to

Error message

CLAUDE_CODE_PATH is set to "${settings.CLAUDE_CODE_PATH}" but the file does not exist.

What it means

find-claude-executable's first resolution stage: settings.CLAUDE_CODE_PATH is set (tilde-expanded defensively, since existsSync and posix_spawn take the string verbatim) but the file does not exist, so resolution aborts before probing any discovered candidates. An explicitly configured path is authoritative — a bad value is an error, not a hint to silently fall back to PATH search.

Solutions

  1. Point CLAUDE_CODE_PATH at the real binary location (check `which claude` or `command -v claude`).
  2. If the CLI is gone, reinstall it (npm install -g @anthropic-ai/claude-code) or remove CLAUDE_CODE_PATH entirely so PATH discovery takes over.
  3. Verify the path with ls after tilde expansion; remember no shell runs here, so env vars like $HOME inside the value are not expanded.

Example fix

// settings.json before
{ "CLAUDE_CODE_PATH": "~/.local/bin/claude-v1" }

// after
{ "CLAUDE_CODE_PATH": "~/.local/bin/claude" }
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';
import { expandTilde } from './tilde.js';
const configured = settings.CLAUDE_CODE_PATH;
if (configured && !existsSync(expandTilde(configured, os.homedir()))) {
  throw new Error(`CLAUDE_CODE_PATH is stale: ${configured} — run \`which claude\` and update settings.json`);
}

Prevention

When it happens

Trigger: settings.json contains a stale path after the CLI was moved, upgraded via a different package manager, or uninstalled; a typo in the path; the file lives on a mount that is not mounted (network drive, encrypted home not unlocked); literal '~' in a config edited outside SettingsRoutes (handled) mixed with other expansions that are not.

Common situations: Switching between nvm/brew/npm installs that relocate the claude binary; dotfiles synced to a new machine where the path differs; containers where the configured path belongs to the host, not the image.

Related errors


AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20). Data as JSON: /api/errors/d9429303ef5940ab. Report an issue: GitHub.

Appendix: source

Thrown at src/shared/find-claude-executable.ts:295

export function findClaudeExecutable(logComponent: Component = 'SDK'): string {
  if (cachedResolution && cachedResolution.expiresAtMs > Date.now() && _internals.existsSync(cachedResolution.path)) {
    return cachedResolution.path;
  }
  cachedResolution = null;

  const settings = _internals.loadSettings();

  // --- 1. Explicit configured path ----------------------------------------
  if (settings.CLAUDE_CODE_PATH) {
    // A user who types `~/.local/bin/claude` in settings.json expects the shell
    // convention, but nothing here runs through a shell — existsSync and
    // posix_spawn take the string verbatim, so a literal `~` fails with ENOENT.
    // Expand it defensively at read time so both the existence check and every
    // probe spawn see a real absolute path (SettingsRoutes also normalizes on
    // write; this covers files edited by hand).
    const configuredPath = expandTilde(settings.CLAUDE_CODE_PATH, _internals.homedir());
    if (!_internals.existsSync(configuredPath)) {
      throw new Error(
        `CLAUDE_CODE_PATH is set to "${settings.CLAUDE_CODE_PATH}" but the file does not exist.`
      );
    }

    const probe = probeCandidate(configuredPath);
    if (probe.kind === 'capable') {
      logger.info(logComponent, `Using configured CLAUDE_CODE_PATH: ${configuredPath} (${probe.version})`);
      cachedResolution = {
        path: configuredPath,
        version: probe.version,
        expiresAtMs: Date.now() + RESOLUTION_CACHE_TTL_MS,
      };
      return configuredPath;
    }
    if (probe.kind === 'incompatible') {
      throw new Error(
        `CLAUDE_CODE_PATH is set to "${settings.CLAUDE_CODE_PATH}" (${probe.version}) but that CLI is too old for claude-mem — ` +
        `it rejects flags every memory agent spawn requires (${probe.detail}). ${updateInstructions()}`

View on GitHub (pinned to e2d1df569a)