Repository navigation
fix(resolution): skip oversized files when chasing imports/re-exports — a single large asset import OOMs the whole index - #1288
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
|
Friendly ping — this has been open since mid-July, and I just re-verified that the bug is still live on Checked against
(The second one passes on The branch is still conflict-free against |
ecccb95 to
7992f42
Compare
|
Thank you for the precise root cause and the two-file repro, @colinli007. The same guard landed as #2006, which shipped in 1.6.1: the resolver checks a file's size before reading it and treats anything over the 1 MB source limit as unreadable, so an imported video or an oversized barrel is never decoded or chased. Your test's cases behave correctly on current main, so we're closing this as fixed. |
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