abhigyanpatwari/GitNexus · error · Error

${TRUSTED_CACHE_DIRECTORY_ENV} must name a pre-existing prot

Error message

${TRUSTED_CACHE_DIRECTORY_ENV} must name a pre-existing protected non-symlink directory

What it means

Thrown by trustedEnvironmentCacheDirectory when the configured path is syntactically absolute (passes error 91's check) but lstat/realpath fail or show it is not a real directory. The cache directory must pre-exist as a plain directory the analyzer can write to; the analyzer will NOT create the env-var-configured location (unlike the options.cacheDirectory override, which it does mkdir).

Source

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

  return process.platform === 'win32' ? left.toLowerCase() === right.toLowerCase() : left === right;
}

function trustedEnvironmentCacheDirectory(): string | null {
  const configured = process.env[TRUSTED_CACHE_DIRECTORY_ENV];
  if (configured === undefined) return null;
  if (configured.length === 0 || configured.includes('\0') || !path.isAbsolute(configured)) {
    throw new Error(`${TRUSTED_CACHE_DIRECTORY_ENV} must name an absolute protected directory`);
  }
  const normalized = path.normalize(configured);
  let resolved: string;
  try {
    const link = lstatSync(normalized);
    if (!link.isDirectory() || link.isSymbolicLink()) {
      throw new Error('not a real directory');
    }
    resolved = realpathSync.native(normalized);
  } catch {
    throw new Error(
      `${TRUSTED_CACHE_DIRECTORY_ENV} must name a pre-existing protected non-symlink directory`,
    );
  }
  // Reject junctions/symlinked ancestors as well as a symlink final component.
  // The environment variable is an explicit trust assertion, but its spelling
  // must still bind exactly to the directory the cache will use.
  if (!pathsEqual(path.resolve(normalized), resolved)) {
    throw new Error(`${TRUSTED_CACHE_DIRECTORY_ENV} must not traverse symbolic links or junctions`);
  }
  return resolved;
}

function cacheDirectory(
  options: AnalyzerIdentityResolveOptions,
  packageRoot: string,
  buildRoot: string,
): string | null {
  // An explicit location is a trusted operator/test override and therefore

View on GitHub (pinned to d540b00184)

Solutions

  1. Pre-create the directory: `mkdir -p /var/cache/gitnexus-analyzer-identity && chmod 700 /var/cache/gitnexus-analyzer-identity`.
  2. Ensure the path is a REAL directory, not a symlink: `ls -ld <path>` should show `drwx...` with no `->`.
  3. If you need it auto-created, pass options.cacheDirectory instead of the env var — cacheDirectory() runs mkdirSync(explicit, {recursive:true, mode:0o700}).
  4. Confirm the mount is up before analyzer start (for network filesystems).

Example fix

# before: env points at a path that was never created
#   export GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/opt/gn-id
#   -> "...must name a pre-existing protected non-symlink directory"
#
# after: pre-create with restrictive perms
#   sudo mkdir -p /opt/gn-id && sudo chmod 700 /opt/gn-id && sudo chown $USER /opt/gn-id
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('node:fs');
const path = require('node:path');
function validateTrustedCacheExists() {
  const v = process.env.GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR;
  if (!v) return;
  const st = fs.lstatSync(v); // throws if missing -> caller must mkdir first
  if (!st.isDirectory()) throw new Error(`${v} is not a directory`);
  if (st.isSymbolicLink()) throw new Error(`${v} is a symlink; use the real path`);
}
// Pre-create before validating:
//   const v = process.env.GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR;
//   if (v) fs.mkdirSync(v, { recursive: true, mode: 0o700 });

Prevention

When it happens

Trigger: trustedEnvironmentCacheDirectory lstatSync(normalized) either throws (ENOENT/permission) or returns a non-directory / a symlink; realpathSync.native then throws. The catch wraps both into this single message. So: a non-existent path, a file, a symlink-to-dir, or an unreadable path all surface here.

Common situations: Operator pointed the env var at a directory they forgot to `mkdir -p`; pointed it at a symlink (forbidden because the trust must bind to the exact real directory); pointed it at a path on a mount not yet available at analyzer start (NFS/cifs race); the directory was removed between deploys.

Related errors


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