abhigyanpatwari/GitNexus · error

Analyzer vendored runtime directory is unavailable: ${vendor

Error message

Analyzer vendored runtime directory is unavailable: ${vendorRoot}

What it means

Thrown by collectVendoredGrammarInputs when recordDirectoryGuard returns false for the `vendor/` directory of the package root. Mirrors error 82 but for the vendored-tree entry point: the analyzer cannot inventory the vendor directory (readdir/stat threw), so it aborts rather than emit an incomplete identity for the vendored grammars.

Source

Thrown at gitnexus/src/core/analyzer-identity.ts:1438

  packageRoot: string,
  directoryGuards: Map<string, DependencyDirectoryGuard>,
  options: AnalyzerIdentityResolveOptions,
  budget: RuntimeArtifactScanBudget,
  limits: AnalyzerIdentityTraversalLimits,
): {
  manifests: DependencyInputs['vendoredManifests'];
  artifacts: RuntimeArtifact[];
} {
  const vendorRoot = path.join(packageRoot, 'vendor');
  if (!existsSync(vendorRoot) || !lstatSync(vendorRoot).isDirectory()) {
    recordDirectoryGuard(directoryGuards, packageRoot);
    return { manifests: [], artifacts: [] };
  }

  const manifests: DependencyInputs['vendoredManifests'] = [];
  const artifacts: RuntimeArtifact[] = [];
  if (!recordDirectoryGuard(directoryGuards, vendorRoot)) {
    throw new Error(`Analyzer vendored runtime directory is unavailable: ${vendorRoot}`);
  }
  const vendorEntries = readDirectory(vendorRoot, options);
  budget.entries += vendorEntries.length;
  if (budget.entries > limits.runtimeEntries) {
    throw new Error(
      `Analyzer runtime payload scan exceeded ${limits.runtimeEntries} entries: ${vendorRoot}`,
    );
  }
  for (const entry of vendorEntries) {
    if (!entry.isDirectory() || !entry.name.startsWith('tree-sitter-')) continue;
    const grammarRoot = path.join(vendorRoot, entry.name);
    const manifestPath = path.join(grammarRoot, 'package.json');
    if (isFile(manifestPath)) {
      options.onCacheMissWork?.({ kind: 'manifest-read', path: manifestPath });
      const read = readStableFileWithinBudget(manifestPath, budget, limits.runtimeBytes);
      manifests.push({
        canonicalPath: `vendor:${entry.name}/package.json`,
        absolutePath: manifestPath,

View on GitHub (pinned to d540b00184)

Solutions

  1. Verify permissions and readability: `ls -la <packageRoot>/vendor` and ensure the analyzer uid can read+execute it.
  2. Re-materialize the vendored grammars: re-run the package's postinstall or `npm rebuild <pkg>` to repopulate vendor/.
  3. Run with no concurrent writers touching vendor/ during identity resolution.
  4. If the platform lacks the optional-grammar toolchain, set GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1 so the optional grammars are absent rather than half-installed.

Example fix

// before: vendor/ owned by root, analyzer runs as non-root
//   -> "Analyzer vendored runtime directory is unavailable: /pkg/vendor"
//
// after: fix ownership and rebuild grammars
//   $ sudo chown -R $(id -u):$(id -g) vendor/
//   $ npm rebuild
Defensive patterns

Strategy: try-catch

Validate before calling

const fs = require('node:fs');
const path = require('node:path');
function assertVendorReadable(packageRoot) {
  const vendor = path.join(packageRoot, 'vendor');
  if (!fs.existsSync(vendor)) return;
  const st = fs.lstatSync(vendor);
  if (!st.isDirectory()) throw new Error(`${vendor} is not a directory`);
  try { fs.readdirSync(vendor); }
  catch (e) { throw new Error(`${vendor} is not readable by uid ${process.getuid?.()}: ${e.message}`); }
}
// assertVendorReadable(process.cwd());

Try / catch

try {
  identity = resolveAnalyzerRunnerIdentity(analyzerModuleUrl, options);
} catch (err) {
  if (err.message.startsWith('Analyzer vendored runtime directory is unavailable:')) {
    log.error('vendor/ unreadable; run `npm rebuild` or set GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1');
  }
  throw err;
}

Prevention

When it happens

Trigger: collectVendoredGrammarInputs computes vendorRoot = path.join(packageRoot,'vendor'); existsSync confirms it and lstat says directory, but the subsequent recordDirectoryGuard(vendorRoot) fails because snapshotDirectoryInventory throws (permissions lost, directory deleted between existsSync and the guard, or readdir denied).

Common situations: A race where a concurrent `tsc`/postinstall deletes and recreates `vendor/` while identity resolution runs; a container where the `vendor/` tree is owned by a different uid and the analyzer process lacks read/execute permission; an interrupted grammar-prebuild script that left `vendor/` half-populated and unreadable.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/494b1e226613111e. Report an issue: GitHub.