thedotmack/claude-mem · warning

Could not restrict permissions on ${path} to 0600: ${chmodEr

Error message

Could not restrict permissions on ${path} to 0600: ${chmodError instanceof Error ? chmodError.message : String(chmodError)}

What it means

After atomically writing settings.json, the installer tries chmod 0o600 because the file can contain tokens (CMEM Pro setup token, provider API keys) and a umask-default 0644 file would be world-readable. This warning means chmodSync failed — the settings write itself succeeded, but the file may be readable by other users. Deliberately fail-soft, not silent.

Source

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

      }
    }

    const target = envNested
      ? (document.env as Record<string, unknown>)
      : document;
    for (const [key, value] of Object.entries(updates)) {
      target[key] = value;
    }

    writeSettingsJsonAtomic(path, document);
    // settings.json can carry tokens (CMEM Pro setup token, provider API
    // keys); a fresh file inherits the umask (usually 0644), leaving them
    // world-readable. Tighten to owner-only. Fail-soft: a chmod failure must
    // never fail the settings write itself, but it is not silent.
    try {
      chmodSync(path, 0o600);
    } catch (chmodError: unknown) {
      log.warn(`Could not restrict permissions on ${path} to 0600: ${chmodError instanceof Error ? chmodError.message : String(chmodError)}`);
    }
    return true;
  } catch (error: unknown) {
    log.error(`Failed to write settings to ${path}: ${error instanceof Error ? error.message : String(error)}`);
    return false;
  }
}

type ProviderId = 'claude' | 'gemini' | 'openrouter';
/**
 * What the installer prompt may offer. `cmem` is a prompt-only sentinel: picking
 * it configures the generic OpenAI-compatible path (base URL + model + key) and
 * persists CLAUDE_MEM_PROVIDER='openrouter'. The worker only understands
 * 'claude' | 'gemini' | 'openrouter', so 'cmem' must never reach settings.json.
 */
type ProviderChoice = ProviderId | 'cmem';
type ClaudeAccessMode = 'subscription' | 'api-key';
type ClaudeApiMode = 'direct' | 'gateway';

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Fix manually: `chmod 600 ~/.claude-mem/settings.json` (on POSIX) and verify with `stat -c %a`.
  2. On Windows/network filesystems, rely on ACLs instead: restrict the folder so only your user can read it.
  3. If secrets were written while the file was group/world-readable, rotate them (API keys, `npx claude-mem server keys rotate`) — the warning means exposure was possible.
  4. Move ~/.claude-mem onto a POSIX filesystem if the host mount permanently ignores modes.

Example fix

# after seeing this warning, tighten manually and verify:
chmod 600 ~/.claude-mem/settings.json
stat -c '%a %n' ~/.claude-mem/settings.json  # expect: 600
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify post-conditions after install instead of trusting the chmod:
import { statSync } from 'node:fs';
const mode = statSync(`${process.env.HOME}/.claude-mem/settings.json`).mode & 0o777;
if (mode !== 0o600) {
  // on POSIX tighten manually; on Windows/ACL fs rely on folder ACLs
}

Try / catch

// The correct pattern is exactly what the installer does — fail-soft but loud:
try { chmodSync(path, 0o600); }
catch (e) { log.warn(`permissions not restricted: ${e instanceof Error ? e.message : e}`); }

Prevention

When it happens

Trigger: chmodSync throwing: filesystems that do not support POSIX modes (Windows FAT, some network mounts, exFAT), the file deleted/moved by another process between write and chmod, or running without ownership of the file.

Common situations: HOME on a Windows drive or SMB/NFS mount without Unix permissions; container with a volume that ignores mode bits; another agent rotating the settings file concurrently.

Related errors


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