{"record":{"id":"494b1e226613111e","repo":"abhigyanpatwari/GitNexus","slug":"analyzer-vendored-runtime-directory-is-unavailable","errorCode":null,"errorMessage":"Analyzer vendored runtime directory is unavailable: ${vendorRoot}","messagePattern":"Analyzer vendored runtime directory is unavailable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/analyzer-identity.ts","lineNumber":1440,"sourceCode":"  packageRoot: string,\n  directoryGuards: Map<string, DependencyDirectoryGuard>,\n  options: AnalyzerIdentityResolveOptions,\n  budget: RuntimeArtifactScanBudget,\n  limits: AnalyzerIdentityTraversalLimits,\n): {\n  manifests: DependencyInputs['vendoredManifests'];\n  artifacts: RuntimeArtifact[];\n} {\n  const vendorRoot = path.join(packageRoot, 'vendor');\n  if (!existsSync(vendorRoot) || !lstatSync(vendorRoot).isDirectory()) {\n    recordDirectoryGuard(directoryGuards, packageRoot);\n    return { manifests: [], artifacts: [] };\n  }\n\n  const manifests: DependencyInputs['vendoredManifests'] = [];\n  const artifacts: RuntimeArtifact[] = [];\n  if (!recordDirectoryGuard(directoryGuards, vendorRoot)) {\n    throw new Error(`Analyzer vendored runtime directory is unavailable: ${vendorRoot}`);\n  }\n  const vendorEntries = readDirectory(vendorRoot, options);\n  budget.entries += vendorEntries.length;\n  if (budget.entries > limits.runtimeEntries) {\n    throw new Error(\n      `Analyzer runtime payload scan exceeded ${limits.runtimeEntries} entries: ${vendorRoot}`,\n    );\n  }\n  for (const entry of vendorEntries) {\n    if (!entry.isDirectory() || !entry.name.startsWith('tree-sitter-')) continue;\n    const grammarRoot = path.join(vendorRoot, entry.name);\n    const manifestPath = path.join(grammarRoot, 'package.json');\n    if (isFile(manifestPath)) {\n      options.onCacheMissWork?.({ kind: 'manifest-read', path: manifestPath });\n      const read = readStableFileWithinBudget(manifestPath, budget, limits.runtimeBytes);\n      manifests.push({\n        canonicalPath: `vendor:${entry.name}/package.json`,\n        absolutePath: manifestPath,","sourceCodeStart":1422,"sourceCodeEnd":1458,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/core/analyzer-identity.ts#L1422-L1458","documentation":"collectVendoredGrammarInputs first checks the vendor/ directory exists, then calls recordDirectoryGuard(vendorRoot) to register a tamper guard on it; if that registration returns false the vendored runtime directory is considered unavailable/unstable and the error is thrown. It protects against the vendor directory appearing then disappearing or being unstatable between the two checks (TOCTOU), which would otherwise let an unguarded directory mutate after identity computation.","triggerScenarios":"resolveAnalyzerRunnerIdentity() on a package whose <packageRoot>/vendor exists and is a directory, but recordDirectoryGuard(vendorRoot) fails — typically because lstat/stat on the directory errors (permission denied, disappearing mid-scan, NFS/ephemeral mounts) after existsSync already passed.","commonSituations":"vendor/ mounted on a flaky network filesystem, an antivirus or sync client (Dropbox/OneDrive) locking the directory, a concurrent npm install mutating the tree, or permission changes on the directory between the two syscalls.","solutions":["Verify the directory is readable and stable: ls -la <packageRoot>/vendor run twice; fix permissions if the second stat fails (chmod/chown on the package root).","Stop concurrent installs/sync tools touching the tree and re-run analyze — the guard is racing a mutation.","Move the GitNexus install off network/ephemeral storage onto a local filesystem.","If vendor/ is not actually needed (optional grammars), reinstall the package so the tree is consistent rather than half-materialized."],"exampleFix":"# before\n$ npx gitnexus analyze\n# Analyzer vendored runtime directory is unavailable: /usr/lib/node_modules/gitnexus/vendor\n\n# after: fix permissions and stop the racing sync client\nsudo chown -R \"$USER\" /usr/lib/node_modules/gitnexus\nkillall Dropbox 2>/dev/null || true\nnpx gitnexus analyze","handlingStrategy":"retry","validationCode":"// Verify the vendored grammar directory is stably readable before analyze:\nimport { lstatSync } from 'node:fs';\nfunction vendorRootStable(packageRoot: string): boolean {\n  const vendorRoot = join(packageRoot, 'vendor');\n  for (let i = 0; i < 3; i++) {\n    try {\n      const s = lstatSync(vendorRoot);\n      if (!s.isDirectory()) return false;\n    } catch {\n      return false;\n    }\n  }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await resolveAnalyzerRunnerIdentity(moduleUrl);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('vendored runtime directory is unavailable')) {\n    await stopSyncToolsAndConcurrentInstalls(); // then retry once\n    return resolveAnalyzerRunnerIdentity(moduleUrl);\n  }\n  throw err;\n}","preventionTips":["Install gitnexus on a local filesystem, not NFS/sync-drive mounts.","Pause antivirus/sync clients during analysis of the install tree.","Never run two npm installs against the same tree concurrently.","Check directory permissions after Docker COPY operations that can clobber modes."],"tags":["analyzer-identity","vendored-grammars","filesystem","race-condition"],"backgroundTag":"directory-guard-failed","analyzedSha":"52924ef12c2290ceee4612526a828ec4cdf2047f","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}