thedotmack/claude-mem · error · Error

CLAUDE_CODE_PATH is set to

Error message

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

What it means

findClaudeExecutable resolves the Claude Code CLI binary. If CLAUDE_CODE_PATH is configured in ~/.claude-mem/settings.json, the library expands ~ and checks that the file exists before probing it; when the configured path does not exist on disk it throws immediately rather than falling back to PATH discovery, because an explicit setting means the user wants that exact binary.

Solutions

  1. Verify the path: run `ls $(node -e "console.log(require('os').homedir())")`-style check or simply `ls <configured path>` and correct CLAUDE_CODE_PATH in ~/.claude-mem/settings.json
  2. Remove CLAUDE_CODE_PATH from ~/.claude-mem/settings.json so the library auto-discovers `claude` on PATH
  3. Reinstall Claude Code CLI (`npm install -g @anthropic-ai/claude-code`) if the binary was deleted, then keep the setting pointing at the new absolute path

Example fix

// before (~/.claude-mem/settings.json)
{ "CLAUDE_CODE_PATH": "~/.local/bin/claude" }  // file deleted by reinstall

// after
{ "CLAUDE_CODE_PATH": "/usr/local/bin/claude" }  // verified with ls, or remove the key entirely
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';
import { homedir } from 'os';
const configured = settings.CLAUDE_CODE_PATH?.trim();
if (configured) {
  const p = configured.startsWith('~') ? configured.replace(/^~/, homedir()) : configured;
  if (!existsSync(p)) console.warn(`CLAUDE_CODE_PATH points at missing file: ${p}`);
}

Type guard

function isExistingFile(p: string | undefined): p is string {
  return typeof p === 'string' && p.length > 0 && existsSync(expandTilde(p));
}

Try / catch

try {
  await findClaudeExecutable();
} catch (e) {
  if (e.message.includes('but the file does not exist')) {
    delete settings.CLAUDE_CODE_PATH; // fall back to PATH discovery
  } else throw e;
}

Prevention

When it happens

Trigger: settings.CLAUDE_CODE_PATH is non-empty and expandTilde(...)/existsSync(configuredPath) returns false — the settings file points at a path that is absent (deleted binary, renamed install, wrong directory, machine migrated without the CLI).

Common situations: Hand-edited settings.json with a typo; uninstalling or upgrading Claude Code so the old absolute path (e.g. ~/.npm-global/bin/claude, ~/.local/bin/claude) disappeared; syncing dotfiles across machines where the CLI lives elsewhere.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

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

  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());
    const describedPath = describeConfiguredPath(settings.CLAUDE_CODE_PATH, configuredPath);
    if (!_internals.existsSync(configuredPath)) {
      throw new Error(
        `CLAUDE_CODE_PATH is set to ${describedPath} 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 ${describedPath} (${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 d8bc9755e7)