thedotmack/claude-mem · warning
installPluginDependencies: no package.json at
Error message
installPluginDependencies: no package.json at ${targetDir} What it means
At the end of shutdown, the PID file is removed only when recordedPid matches currentPid; rmSync(pidFilePath, {force:true}) then threw a non-Error value. force already suppresses ENOENT, so realistic Error causes are EPERM/EACCES (ownership changed, container user mismatch, Windows file lock) — but a non-Error throw is warned while the Error twin is only debug-level. Leftover PID files make the next start think a worker is running until the alive check fails.
Solutions
- Inspect `ls -l <pidFilePath>` and fix ownership/permissions (chown/chmod) or delete the stale file manually.
- Run the supervisor consistently under one user account so the writer and remover match.
- On Windows, exclude the state directory from antivirus/indexer scans.
- If a directory now occupies the path, remove it and let the supervisor recreate the file.
Defensive patterns
Strategy: try-catch
Validate before calling
import { accessSync, constants, rmSync } from 'fs';
function removePidFileIfWritable(pidFilePath: string): void {
try {
accessSync(pidFilePath, constants.W_OK);
} catch {
return; // not writable — leave it; the alive-check will reject it next boot
}
try { rmSync(pidFilePath, { force: true }); } catch { /* logged upstream */ }
} Try / catch
try {
rmSync(pidFilePath, { force: true });
} catch (error: unknown) {
if (error instanceof Error) {
logger.debug('SYSTEM', 'Failed to remove PID file', { pidFilePath }, error);
} else {
logger.warn('SYSTEM', 'Failed to remove PID file (non-Error)', { pidFilePath, error: String(error) });
}
} Prevention
- Run writer and cleaner as the same OS user — never mix sudo and normal-user invocations.
- Place state files in a directory the service user owns (XDG-style), not shared roots.
- On Windows, exclude state directories from antivirus and search-indexer scans.
- Stale PID files are self-correcting here (alive check fails), so prefer fixing ownership over manual deletion.
When it happens
Trigger: PID file or its directory owned by root while the supervisor now runs as a normal user; antivirus/indexer holding the file open on Windows; the path replaced by a directory; storage wrappers throwing non-Error values.
Common situations: Running the tool once with sudo then as a user; Docker volume permission mismatches; crashed cleanup reruns; corporate endpoint protection locking files.
Related errors
- Failed to remove PID file
- [ide-detection] Failed to read VS Code extensions directory:
- Unable to acquire Chroma writer lock at
- Unable to remove unreadable Chroma writer lock at
- [uninstall] Could not read
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/54fb9d420c6722a9.
Report an issue: GitHub.
Appendix: source
Thrown at src/npx-cli/install/setup-runtime.ts:428
let version = getUvVersion();
if (!version) {
await new Promise((r) => setTimeout(r, 1000));
version = getUvVersion();
}
if (!version) {
installerError(ErrorSeverity.WARN_CONTINUE, {
component: 'uv-version-probe',
phase: 'setup-runtime',
cause: new Error(`uv at ${uvPath} did not respond to --version after retry`),
}, sum);
return { uvPath, version: 'unknown' };
}
return { uvPath, version };
}
export async function installPluginDependencies(targetDir: string, bunPath: string): Promise<void> {
if (!existsSync(join(targetDir, 'package.json'))) {
throw new Error(`installPluginDependencies: no package.json at ${targetDir}`);
}
const bunCmd = IS_WINDOWS && bunPath.includes(' ') ? `"${bunPath}"` : bunPath;
// Per CHANGELOG v12.6.1 -> v12.6.2: tree-sitter-swift's nested
// tree-sitter-cli postinstall downloads a Rust binary and can hang the
// install. Bun honors trustedDependencies; npm does not. We additionally
// pass --ignore-scripts as belt-and-suspenders and bound it with a timeout.
// Async exec (not execSync): a blocked event loop freezes the installer's
// clack spinner for the duration of the install, which reads as a stall.
const runBunInstall = (): Promise<void> =>
new Promise<void>((resolve, reject) => {
exec(`${bunCmd} install --frozen-lockfile --ignore-scripts`, {
cwd: targetDir,
timeout: INSTALL_TIMEOUT_MS,
maxBuffer: 16 * 1024 * 1024,
...(IS_WINDOWS ? { shell: process.env.ComSpec ?? 'cmd.exe' } : {}),
}, (error, stdout, stderr) =>View on GitHub (pinned to e2d1df569a)