{"record":{"id":"23316b332152629b","repo":"abhigyanpatwari/GitNexus","slug":"analyzer-package-lock-is-not-a-regular-file-can","errorCode":null,"errorMessage":"Analyzer package lock is not a regular file: ${candidate}","messagePattern":"Analyzer package lock is not a regular file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/analyzer-identity.ts","lineNumber":976,"sourceCode":"    try {\n      const link = lstatSync(candidate);\n      if (link.isFile()) return path.resolve(candidate);\n      if (link.isSymbolicLink()) {\n        try {\n          const target = statSync(candidate);\n          if (!target.isFile()) {\n            throw new Error(\n              `Analyzer package lock symbolic link does not resolve to a file: ${candidate}`,\n            );\n          }\n        } catch {\n          throw new Error(\n            `Analyzer package lock symbolic link does not resolve to a file: ${candidate}`,\n          );\n        }\n        return path.resolve(candidate);\n      }\n      throw new Error(`Analyzer package lock is not a regular file: ${candidate}`);\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n    }\n    const parent = path.dirname(cursor);\n    if (parent === cursor) return null;\n    cursor = parent;\n  }\n}\n\nfunction runtimePackageLocator(packageRoot: string, runtimeRoot: string): string {\n  if (runtimeRoot === packageRoot) return 'root:.';\n  const relative = path.relative(packageRoot, runtimeRoot).split(path.sep).join('/');\n  return `relative:${relative}`;\n}\n\n/** Protocols that name a checkout-local package instead of a registry tarball. */\nconst LOCAL_LINK_PROTOCOL_PATTERN = /^(?:file|link|workspace|portal):/;\n/** npm's bare local-path shorthands: `./x`, `../x`, `/x`, `~/x`, `C:\\x`. */","sourceCodeStart":958,"sourceCodeEnd":994,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/core/analyzer-identity.ts#L958-L994","documentation":"If a candidate package-lock.json exists but lstat reports neither a regular file nor a symbolic link (a directory, FIFO, socket, device), the walk throws instead of skipping it. Skipping would mean an install whose frozen dependency state is unreadable still gets a 'stable' identity, which the receipt model forbids — the lockfile is a semantic input. ENOENT is the only swallowed case (normal 'no lockfile here' continuation).","triggerScenarios":"A directory or special file literally named package-lock.json in the package root or any ancestor directory while resolveAnalyzerRunnerIdentity locates the lockfile — e.g. someone made package-lock.json/ a folder to hold multiple lockfiles, or a tool created a lock/pid artifact with that name.","commonSituations":"Monorepos that store per-package lockfiles in a directory named package-lock.json/; scripts writing lock markers with unlucky names; container images copying a directory over the lockfile path.","solutions":["Rename or remove the offending path: it must be a regular file (or a symlink to one) if it keeps the name package-lock.json.","Move collected lockfiles out of that directory and place the active one at the expected file path.","Check ancestors too — the walk inspects every level up to the filesystem root."],"exampleFix":"# before\npackage-lock.json/\n  ├── a/package-lock.json\n  └── b/package-lock.json\n\n# after\npackage-lock.json        # regular file (the active lockfile)\nlocks/\n  ├── a/package-lock.json\n  └── b/package-lock.json","handlingStrategy":"validation","validationCode":"import { lstatSync } from 'node:fs';\nimport path from 'node:path';\n\nfunction lockfileCandidatesAreRegular(packageRoot: string): boolean {\n  let cursor = packageRoot;\n  while (true) {\n    const candidate = path.join(cursor, 'package-lock.json');\n    try {\n      const stat = lstatSync(candidate);\n      if (!stat.isFile() && !stat.isSymbolicLink()) return false;\n    } catch {\n      /* ENOENT is fine */\n    }\n    const parent = path.dirname(cursor);\n    if (parent === cursor) return true;\n    cursor = parent;\n  }\n}","typeGuard":"function isLockfileNotRegularFileError(error: unknown): boolean {\n  return error instanceof Error && /^Analyzer package lock is not a regular file:/.test(error.message);\n}","tryCatchPattern":"try {\n  identity = resolveAnalyzerRunnerIdentity(import.meta.url);\n} catch (error) {\n  if (isLockfileNotRegularFileError(error)) {\n    reportUserError(`package-lock.json exists but is not a file: ${error.message}; rename or remove it.`);\n  }\n  throw error;\n}","preventionTips":["Never store multiple lockfiles inside a directory named package-lock.json/.","Audit ancestor directories for stray artifacts with that exact name when provisioning environments."],"tags":["gitnexus","analyzer-identity","package-lock","filesystem","special-files"],"backgroundTag":"not-a-regular-file","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}