{"record":{"id":"e2b28a86d66a4466","repo":"abhigyanpatwari/GitNexus","slug":"analyzer-runtime-payload-directory-is-unavailable","errorCode":null,"errorMessage":"Analyzer runtime payload directory is unavailable: ${absoluteDir}","messagePattern":"Analyzer runtime payload directory is unavailable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/analyzer-identity.ts","lineNumber":1320,"sourceCode":"  return lower !== 'package.json';\n}\n\nfunction collectArtifacts(\n  root: string,\n  canonicalPrefix: string,\n  directoryGuards: Map<string, DependencyDirectoryGuard>,\n  options: AnalyzerIdentityResolveOptions,\n  budget: RuntimeArtifactScanBudget,\n  limits: AnalyzerIdentityTraversalLimits,\n): RuntimeArtifact[] {\n  const artifacts: RuntimeArtifact[] = [];\n  const pending: Array<{ absoluteDir: string; depth: number }> = [{ absoluteDir: root, depth: 0 }];\n  while (pending.length > 0) {\n    const next = pending.pop();\n    if (!next) break;\n    const { absoluteDir, depth } = next;\n    if (!recordDirectoryGuard(directoryGuards, absoluteDir)) {\n      throw new Error(`Analyzer runtime payload directory is unavailable: ${absoluteDir}`);\n    }\n    const entries = readDirectory(absoluteDir, options);\n    budget.entries += entries.length;\n    if (budget.entries > limits.runtimeEntries) {\n      throw new Error(\n        `Analyzer runtime payload scan exceeded ${limits.runtimeEntries} entries: ${root}`,\n      );\n    }\n    for (const entry of entries) {\n      const absolutePath = path.join(absoluteDir, entry.name);\n      const relativePath = path.relative(root, absolutePath).split(path.sep).join('/');\n      const stat = lstatSync(absolutePath);\n      // Nested dependencies are collected from their manifests as separate\n      // packages. Only prune those separately traversed trees and VCS\n      // metadata; generic cache/model directories can contain loadable code,\n      // native addons, Wasm modules, or data consumed by the runtime.\n      //\n      // Pruning is decided by NAME alone. These four names never carry analyzer","sourceCodeStart":1302,"sourceCodeEnd":1338,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus/src/core/analyzer-identity.ts#L1302-L1338","documentation":"Thrown by collectArtifacts when recordDirectoryGuard returns false for a directory it is about to scan. recordDirectoryGuard fails (returns false) only when snapshotDirectoryInventory throws — meaning the directory cannot be inventoried via readdir+stat. The throw aborts the runtime-payload scan because the identity receipt cannot cover a directory it cannot observe.","triggerScenarios":"collectArtifacts pops a pending directory and calls recordDirectoryGuard(directoryGuards, absoluteDir); if the directory was deleted, lost permissions, or turned into a broken symlink/non-directory between enqueue and scan, snapshotDirectoryInventory throws and recordDirectoryGuard returns false, triggering this error.","commonSituations":"A concurrent process (build, IDE, package manager) deleting or moving directories under the package while the analyzer resolves its identity; a node_modules entry that is a dangling symlink to a removed target; permission errors after a `chown`/container rebuild where the analyzer process cannot read a subdirectory; an OS-level antivirus quarantining a directory mid-scan.","solutions":["Re-run the analyze once the filesystem is quiescent — close concurrent builds/installs/IDE indexers and retry.","Check the named absoluteDir: `ls -la <absoluteDir>` and `readlink -f <absoluteDir>` to confirm it exists and is readable.","If a dangling symlink is the cause, repair or remove it (`npm install` to rebuild node_modules, or `rm` the broken link).","Run the analyzer from a clean checkout or freshly installed tree so no partial deletion races the scan."],"exampleFix":"// before: analyzer runs while `tsc --watch` deletes and recreates dist/\n//   -> \"Analyzer runtime payload directory is unavailable: /pkg/dist\"\n//\n// after: stop concurrent writers, then resolve identity\n//   $ pkill -f tsc  (or close the watch)\n//   $ node .gitnexus/run.cjs analyze --index-only","handlingStrategy":"try-catch","validationCode":"const fs = require('node:fs');\nconst path = require('node:path');\nfunction isDirectoryReadable(dir) {\n  let st;\n  try { st = fs.lstatSync(dir); } catch { return false; }\n  if (!st.isDirectory()) return false;\n  try { fs.readdirSync(dir); return true; } catch { return false; }\n}\n// Pre-walk the package tree to confirm every dir is readable before resolveAnalyzerRunnerIdentity.\n// Only a shallow check; the real scan is deeper, but this catches the common permission/deletion case.","typeGuard":null,"tryCatchPattern":"try {\n  identity = resolveAnalyzerRunnerIdentity(analyzerModuleUrl, options);\n} catch (err) {\n  if (err.message.startsWith('Analyzer runtime payload directory is unavailable:')) {\n    const dir = err.message.split(': ').slice(1).join(': ');\n    log.warn(`Directory ${dir} vanished during identity resolution; ensure no concurrent build is mutating the tree.`);\n    // do not retry in a tight loop; surface to the user / scheduler with backoff\n  }\n  throw err;\n}","preventionTips":["Run identity resolution only when the filesystem is quiescent (no concurrent build/install).","Pre-validate read+execute permission on the package tree with the analyzer process's uid.","Repair node_modules (`rm -rf node_modules && npm install`) when dangling/broken directories appear.","Avoid running the analyzer inside a container whose overlayfs is still applying layer writes."],"tags":["analyzer-identity","filesystem","directory-guard","toctou"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}