{"record":{"id":"f182bfe6012d66cb","repo":"abhigyanpatwari/GitNexus","slug":"trusted-cache-directory-env-must-name-a-pre-exi","errorCode":null,"errorMessage":"${TRUSTED_CACHE_DIRECTORY_ENV} must name a pre-existing protected non-symlink directory","messagePattern":"(.+?) must name a pre-existing protected non-symlink directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/analyzer-identity.ts","lineNumber":2079,"sourceCode":"  return process.platform === 'win32' ? left.toLowerCase() === right.toLowerCase() : left === right;\n}\n\nfunction trustedEnvironmentCacheDirectory(): string | null {\n  const configured = process.env[TRUSTED_CACHE_DIRECTORY_ENV];\n  if (configured === undefined) return null;\n  if (configured.length === 0 || configured.includes('\\0') || !path.isAbsolute(configured)) {\n    throw new Error(`${TRUSTED_CACHE_DIRECTORY_ENV} must name an absolute protected directory`);\n  }\n  const normalized = path.normalize(configured);\n  let resolved: string;\n  try {\n    const link = lstatSync(normalized);\n    if (!link.isDirectory() || link.isSymbolicLink()) {\n      throw new Error('not a real directory');\n    }\n    resolved = realpathSync.native(normalized);\n  } catch {\n    throw new Error(\n      `${TRUSTED_CACHE_DIRECTORY_ENV} must name a pre-existing protected non-symlink directory`,\n    );\n  }\n  // Reject junctions/symlinked ancestors as well as a symlink final component.\n  // The environment variable is an explicit trust assertion, but its spelling\n  // must still bind exactly to the directory the cache will use.\n  if (!pathsEqual(path.resolve(normalized), resolved)) {\n    throw new Error(`${TRUSTED_CACHE_DIRECTORY_ENV} must not traverse symbolic links or junctions`);\n  }\n  return resolved;\n}\n\nfunction cacheDirectory(\n  options: AnalyzerIdentityResolveOptions,\n  packageRoot: string,\n  buildRoot: string,\n): string | null {\n  // An explicit location is a trusted operator/test override and therefore","sourceCodeStart":2061,"sourceCodeEnd":2097,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/core/analyzer-identity.ts#L2061-L2097","documentation":"After passing the absolute-path check, the trusted cache directory must be an already-existing real directory: lstat must succeed, report a directory, and not a symbolic link, and realpathSync.native must resolve. Any miss (missing directory, symlink final component, file instead of directory, permission error surfaced as a thrown syscall error) is collapsed into this error. The cache directory must be pre-created by the operator because the code intentionally does not mkdir an env-declared trusted path.","triggerScenarios":"GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR points at a directory that does not exist yet, points at a symlink (ln -s), points at a regular file, or is unreadable due to permissions — then trustedEnvironmentCacheDirectory() lstat/realpath throws and the error is rethrown with the guidance message.","commonSituations":"Operators expecting the tool to create the cache dir (common with XDG-style conventions), pointing at /tmp symlinks on macOS (/tmp -> /private/tmp), Docker volume mounts that arrive as symlinks, or a typo'd path that was never mkdir'd.","solutions":["Create the directory before running: mkdir -p /var/cache/gitnexus-identity && export GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/var/cache/gitnexus-identity.","If the path is a symlink, point the variable directly at the real target (on macOS use /private/tmp not /tmp).","Verify it is a plain directory: [ -d \"$DIR\" ] && [ ! -L \"$DIR\" ] && echo ok.","Fix ownership/permissions so the process can lstat and realpath it."],"exampleFix":"# before\nexport GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=/tmp/gnx-id-cache\nnpx gitnexus analyze\n# ...must name a pre-existing protected non-symlink directory\n\n# after (note: /tmp is a symlink on macOS; create a real dir first)\nmkdir -p \"$HOME/.cache/gnx-id-cache\"\nexport GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR=\"$HOME/.cache/gnx-id-cache\"\nnpx gitnexus analyze","handlingStrategy":"validation","validationCode":"// Pre-flight the trusted cache dir exactly the way the tool does:\nimport { lstatSync, realpathSync } from 'node:fs';\nimport { isAbsolute } from 'node:path';\nfunction trustedCacheDirOk(dir: string): boolean {\n  if (!dir || dir.includes('\\0') || !isAbsolute(dir)) return false;\n  try {\n    const s = lstatSync(dir);\n    return s.isDirectory() && !s.isSymbolicLink();\n  } catch {\n    return false; // must pre-exist; the tool will not create it\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  spawnSync('gitnexus', ['analyze']);\n} catch (err) {\n  if (String((err as Error).message).includes('pre-existing protected non-symlink directory')) {\n    mkdirSync(process.env.GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR!, { recursive: true }); // then point at the real path\n    process.env.GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR = realpathSync(process.env.GITNEXUS_ANALYZER_IDENTITY_CACHE_DIR!);\n    return spawnSync('gitnexus', ['analyze']);\n  }\n  throw err;\n}","preventionTips":["Provision the cache directory in your setup script (mkdir -p) before first run; the env path is never auto-created.","Never point the variable at a symlink or a macOS /tmp alias path.","Include the directory creation in Dockerfiles and CI bootstrap steps.","Prefer $HOME- or /var/cache-based paths that are stable and real."],"tags":["analyzer-identity","cache","environment-variable","symlink","directory-validation"],"backgroundTag":"invalid-env-var-value","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"}