thedotmack/claude-mem · warning

Could not read ${configFile}: ${error instanceof Error ? err

Error message

Could not read ${configFile}: ${error instanceof Error ? error.message : String(error)}

What it means

A log.warn from the installer's PATH setup: readFileSync on the detected shell config (~/.zshrc, ~/.bashrc, config.fish, …) failed although existsSync passed. The handler only warns and continues with existing = ''. Note the downstream consequence: since existing is empty, the check `existing.includes(claudeBinDir)` is false and the code will try writeFileSync(configFile, block) — attempting to append the PATH export to a file it could not read, which normally fails too (see the 'Could not update' warning) but could overwrite a readable-write-but-unreadable file.

Source

Thrown at src/npx-cli/commands/install.ts:524

  if (!existsSync(claudeBinary)) return;

  const currentPath = process.env.PATH ?? '';
  const pathEntries = currentPath.split(':');
  if (pathEntries.includes(claudeBinDir)) return;

  const { path: configFile, shell } = detectShellConfigFile();
  const binPathLiteral = '$HOME/.local/bin';
  const exportLine = shell === 'fish'
    ? `set -gx PATH ${claudeBinDir} $PATH`
    : `export PATH="${binPathLiteral}:$PATH"`;

  let existing = '';
  if (existsSync(configFile)) {
    try {
      existing = readFileSync(configFile, 'utf-8');
    } catch (error: unknown) {
      // [ANTI-PATTERN IGNORED]: the failure is already surfaced to the user via the interactive-aware log.warn wrapper below (p.log.warn in a TTY, console.warn otherwise); a raw console call here would double-print.
      log.warn(`Could not read ${configFile}: ${error instanceof Error ? error.message : String(error)}`);
    }
  } else {
    try {
      mkdirSync(dirname(configFile), { recursive: true });
    } catch {
      // Best-effort directory creation.
    }
  }

  if (existing.includes(claudeBinDir) || existing.includes(binPathLiteral)) {
    log.info(`Claude Code PATH already configured in ${configFile}`);
  } else {
    try {
      const trailing = existing.length === 0 || existing.endsWith('\n') ? '' : '\n';
      const block = `${trailing}\n# Added by claude-mem installer for Claude Code\n${exportLine}\n`;
      writeFileSync(configFile, existing + block, 'utf-8');
      log.success(`Added Claude Code to PATH in ${configFile}`);
    } catch (error: unknown) {

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Fix read permissions first: sudo chown $USER ~/.zshrc && chmod u+rw ~/.zshrc
  2. Back up your shell configs before running any installer that edits them
  3. Re-run install; if you then see 'Could not update', apply the printed manual echo command instead

Example fix

# before
$ ls -l ~/.zshrc
-rw------- 1 root root … /home/user/.zshrc

# after
$ sudo chown $USER ~/.zshrc && chmod u+rw ~/.zshrc
$ npx claude-mem install  # PATH export appended cleanly
Defensive patterns

Strategy: validation

Validate before calling

import { accessSync, constants } from 'node:fs';
function configReadable(file: string): boolean {
  try { accessSync(file, constants.R_OK | constants.W_OK); return true; } catch { return false; }
}

Prevention

When it happens

Trigger: Shell config exists with no read permission for the current user (write-only oddities, root-owned .zshrc from a past sudo edit); a dangling symlink that existsSync follows to nothing in a way that throws; ACL-restricted home directories.

Common situations: Earlier sudo vim ~/.zshrc left the file root-owned mode 600; enterprise ACL setups; running the installer in an environment with an unusual HOME (CI runners, containers) where dotfiles are managed externally.

Related errors


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