fix(resolution): skip oversized files when chasing imports/re-exports — a single large asset import OOMs the whole index#1288
Open
li1164267803 wants to merge 1 commit into
Conversation
7d4f1a8 to
9d38b80
Compare
Reference resolution follows import targets verbatim, so an asset import (import video from "./intro.mp4") hands readFileCached() a path extraction never parsed. The content can't answer an import/re-export chase — extraction skips files over MAX_FILE_SIZE, so they have no nodes — but resolution read them whole anyway, decoded them as UTF-8, and regex-scanned them. On a real project a single ~240 MB video import OOM'd an 8 GB heap at "Resolving refs" ~65%, killing every codegraph init (reproducible with two files: one .ts importing one 240 MB binary). Mirror extraction's guard in readFileCached(): stat first, and treat anything over 1 MB as unreadable (cached null), making oversized files as invisible to resolution as they already are to extraction. Regression tests: an oversized barrel's re-export chain must not be chased (pre-fix it produced a calls edge through a file the graph doesn't contain), and a project importing a >1 MB binary must index. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9d38b80 to
ecccb95
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(resolution): skip oversized files when chasing imports/re-exports — a single large asset import OOMs the whole index
Problem
codegraph initdies withFATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memoryduring "Resolving refs", reproducibly at the same ref, on a mid-size React/TS project (1,161 files, ~54k refs). Raising the heap doesn't help — an 8 GB heap (NODE_OPTIONS=--max-old-space-size=8192, honored by the vendored runtime) dies at the same ~65%. The background daemon OOMs the same way on every session, so the project can't be indexed at all. Affects 1.3.1 and 1.4.1; 0.9.9 was fine.Minimal repro — two files:
Root cause
Reference resolution follows import targets verbatim. An asset import —
import Emilia from "@/assets/Emilia.mp4"in the real project (a 243 MB video),./big.mp4above — hands the resolver a path that extraction never parsed. Extraction has aMAX_FILE_SIZEguard (1 MB) precisely so vendored blobs and bundles stay out of the graph, but resolution'sreadFileCached()has no such guard: the import/re-export chase (getReExports,getImportMappings) reads the target whole, decodes hundreds of MB of binary as UTF-8, and regex-scans the resulting string for re-exports (for a non-JS extension the language re-key falls back to the consumer's language, so the mp4 bytes are scanned as TypeScript). The transient strings and match arrays blow through any heap limit. Since the file was never parsed, the read can never produce a resolution — the cost buys nothing.Instrumentation pinpointing it (per-ref log, 2 GB heap): heap is at 110 MB entering the
Emiliaimport ref, then the process dies inside that singleresolveOnecall.Fix
Mirror extraction's guard in
readFileCached():statbefore reading, and treat anything over 1 MB as unreadable (cachednull). Oversized files become exactly as invisible to resolution as they already are to extraction — no behavior change for any file the graph can actually contain.Tests
Two regression tests in
__tests__/resolution-oversized-file.test.ts:callsedge through a file the graph doesn't contain (that's the read the OOM rides in on); post-fix the chase stops at the barrelBoth fail before the fix and pass after. Full suite: 139 files, 2,374 passed / 4 skipped — green.
Verified end-to-end: the 240 MB two-file repro and the original 1,161-file project both index completely with a 2 GB heap post-fix (previously OOM'd 8 GB); index integrity confirmed (13,633 nodes / 31,397 edges — 232 more resolved edges than 0.9.9 produced on the same repo).
🤖 Generated with Claude Code