abhigyanpatwari/GitNexus · warning
[node] package.json scan of ${repoRoot} hit the ${SCAN_MAX_D
Error message
[node] package.json scan of ${repoRoot} hit the ${SCAN_MAX_DIRS}-directory cap; workspace packages below it will not resolve What it means
loadNodeWorkspacePackages BFS-scans repoRoot for package.json manifests to enable workspace import resolution; the scan stopped after SCAN_MAX_DIRS (20,000) directories. Workspace packages located below the unscanned portion of the tree will not resolve, degrading import and call resolution for them.
Source
Thrown at gitnexus/src/core/ingestion/import-resolvers/node-workspace-packages.ts:347
/**
* Collect the `package.json` of every ADMITTED workspace package.
*
* Directory-only BFS: the sole files opened are manifests and the workspace
* declaration, so this is far cheaper than the C# namespace scan next door,
* which reads every `.cs` file.
*/
export async function loadNodeWorkspacePackages(
repoRoot: string,
): Promise<NodeWorkspacePackages | null> {
const scope = await loadWorkspaceScope(repoRoot);
const byName = new Map<string, NodeWorkspacePackage>();
const queue: { dir: string; depth: number }[] = [{ dir: repoRoot, depth: 0 }];
let dirsScanned = 0;
while (queue.length > 0) {
if (dirsScanned >= SCAN_MAX_DIRS) {
logger.warn(
`[node] package.json scan of ${repoRoot} hit the ${SCAN_MAX_DIRS}-directory cap; workspace packages below it will not resolve`,
);
break;
}
const { dir, depth } = queue.shift()!;
dirsScanned++;
let entries: import('fs').Dirent[];
try {
entries = await fs.readdir(dir, { withFileTypes: true });
} catch {
continue;
}
for (const entry of entries) {
if (entry.isDirectory()) {
const childDir = path.join(dir, entry.name);
if (isHardcodedIgnoredDirectoryAtPath(repoRoot, childDir)) continue;View on GitHub (pinned to 52924ef12c)
Solutions
- Prune committed vendored trees / node_modules so the directory count drops under 20,000
- Add ignore rules so large generated/vendor subtrees are excluded from the walk
- Verify which packages failed to resolve and accept degraded resolution if the tree is legitimately above the cap
Example fix
# before — committed node_modules pushes repo to 45k dirs repo/node_modules/** (committed) # after — remove and ignore it git rm -r --cached node_modules echo 'node_modules/' >> .gitignore
Defensive patterns
Strategy: validation
Validate before calling
import { readdirSync, statSync } from 'node:fs';
function countDirs(root: string): number {
let n = 0;
const walk = (dir: string) => {
n++;
if (n > 20_000) return;
for (const e of readdirSync(dir, { withFileTypes: true })) {
if (e.isDirectory()) walk(`${dir}/${e.name}`);
}
};
walk(root);
return n;
}
if (countDirs(repoRoot) >= 20_000) {
throw new Error('directory count at/above the 20,000 scan cap — prune vendored trees or add ignore rules');
} Type guard
function withinScanCap(dirCount: number, cap = 20_000): boolean {
return dirCount < cap;
} Prevention
- Never commit node_modules or large vendored SDK trees — they burn the 20,000-directory scan budget
- Keep ignore rules current for generated/vendor directories so the walker prunes them before counting
- After adding packages far down the tree, verify their workspace:* imports resolve; failure to resolve suggests the cap tripped
When it happens
Trigger: A monorepo (or a repo containing committed vendored trees) with more than 20,000 directories under the scan root — the cap trips before the whole tree is enumerated and the loop breaks.
Common situations: Huge pnpm/yarn workspaces; repos that accidentally commit node_modules or vendored SDKs; symptom is workspace:* imports in far-down packages failing to resolve to real symbols.
Related errors
- [node-workspace-extractor] duplicate package name "${manifes
- [rust-workspace-extractor] duplicate crate name "${manifest.
- [python-workspace-extractor] duplicate package "${manifest.n
- [csharp] namespace scan of ${repoRoot} truncated (dir cap ${
AI-assisted analysis of abhigyanpatwari/GitNexus@52924ef12c (2026-08-20).
Data as JSON: /api/errors/87cdb8907c1333df.
Report an issue: GitHub.