{"record":{"id":"54fb9d420c6722a9","repo":"thedotmack/claude-mem","slug":"installplugindependencies-no-package-json-at-ta","errorCode":null,"errorMessage":"installPluginDependencies: no package.json at ${targetDir}","messagePattern":"installPluginDependencies: no package\\.json at (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/npx-cli/install/setup-runtime.ts","lineNumber":428,"sourceCode":"  let version = getUvVersion();\n  if (!version) {\n    await new Promise((r) => setTimeout(r, 1000));\n    version = getUvVersion();\n  }\n  if (!version) {\n    installerError(ErrorSeverity.WARN_CONTINUE, {\n      component: 'uv-version-probe',\n      phase: 'setup-runtime',\n      cause: new Error(`uv at ${uvPath} did not respond to --version after retry`),\n    }, sum);\n    return { uvPath, version: 'unknown' };\n  }\n  return { uvPath, version };\n}\n\nexport async function installPluginDependencies(targetDir: string, bunPath: string): Promise<void> {\n  if (!existsSync(join(targetDir, 'package.json'))) {\n    throw new Error(`installPluginDependencies: no package.json at ${targetDir}`);\n  }\n\n  const bunCmd = IS_WINDOWS && bunPath.includes(' ') ? `\"${bunPath}\"` : bunPath;\n\n  // Per CHANGELOG v12.6.1 -> v12.6.2: tree-sitter-swift's nested\n  // tree-sitter-cli postinstall downloads a Rust binary and can hang the\n  // install. Bun honors trustedDependencies; npm does not. We additionally\n  // pass --ignore-scripts as belt-and-suspenders and bound it with a timeout.\n  // Async exec (not execSync): a blocked event loop freezes the installer's\n  // clack spinner for the duration of the install, which reads as a stall.\n  const runBunInstall = (): Promise<void> =>\n    new Promise<void>((resolve, reject) => {\n      exec(`${bunCmd} install --frozen-lockfile --ignore-scripts`, {\n        cwd: targetDir,\n        timeout: INSTALL_TIMEOUT_MS,\n        maxBuffer: 16 * 1024 * 1024,\n        ...(IS_WINDOWS ? { shell: process.env.ComSpec ?? 'cmd.exe' } : {}),\n      }, (error, stdout, stderr) =>","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/npx-cli/install/setup-runtime.ts#L410-L446","documentation":"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.","triggerScenarios":"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.","commonSituations":"Running the tool once with sudo then as a user; Docker volume permission mismatches; crashed cleanup reruns; corporate endpoint protection locking files.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { accessSync, constants, rmSync } from 'fs';\n\nfunction removePidFileIfWritable(pidFilePath: string): void {\n  try {\n    accessSync(pidFilePath, constants.W_OK);\n  } catch {\n    return; // not writable — leave it; the alive-check will reject it next boot\n  }\n  try { rmSync(pidFilePath, { force: true }); } catch { /* logged upstream */ }\n}","typeGuard":null,"tryCatchPattern":"try {\n  rmSync(pidFilePath, { force: true });\n} catch (error: unknown) {\n  if (error instanceof Error) {\n    logger.debug('SYSTEM', 'Failed to remove PID file', { pidFilePath }, error);\n  } else {\n    logger.warn('SYSTEM', 'Failed to remove PID file (non-Error)', { pidFilePath, error: String(error) });\n  }\n}","preventionTips":["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."],"tags":["supervisor","pid-file","filesystem","permissions","non-error-throw"],"backgroundTag":"file-permission-denied","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}