Skip to content

Commit 99e7ceb

Browse files
committed
fix: sequential WASM grammar loading to fix crash on Node.js v20
web-tree-sitter ≤0.24.x has a race condition when loading multiple WASM grammars concurrently via Promise.all(). The Emscripten glue code shares global state during instantiation, causing cross-language symbol contamination (e.g., 'bad export type for tree_sitter_javascript_external_scanner_create: undefined'). This manifests on Node.js ≤20 but not ≥22 due to differences in V8's WebAssembly.instantiate isolation behavior. Fix: load grammars sequentially with a for..of loop instead of Promise.all(). Also add graceful per-grammar error handling so one failed grammar doesn't crash the entire scanner. Also switch CLI and MCP server to workspace:* for @opencodereview/core to ensure they always use the local build during development. Closes: warden-core#499
1 parent 653b50e commit 99e7ceb

4 files changed

Lines changed: 33 additions & 28 deletions

File tree

packages/cli/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@opencodereview/cli",
33
"version": "2.1.4",
4-
"description": "Detect AI-hallucinated packages, phantom dependencies, and stale APIs in your codebase. Open-source CI/CD quality gate with local Ollama support zero API cost.",
4+
"description": "Detect AI-hallucinated packages, phantom dependencies, and stale APIs in your codebase. Open-source CI/CD quality gate with local Ollama support \u2014 zero API cost.",
55
"type": "module",
66
"bin": {
77
"opencodereview": "./dist/index.js",
@@ -91,7 +91,7 @@
9191
"url": "https://github.com/raye-deng/open-code-review/issues"
9292
},
9393
"dependencies": {
94-
"@opencodereview/core": "^2.1.1",
94+
"@opencodereview/core": "workspace:*",
9595
"glob": "^10.3.0"
9696
},
9797
"devDependencies": {

packages/core/src/parser/manager.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,34 @@ export class ParserManager {
127127
},
128128
});
129129

130-
// Load grammars for all supported languages
130+
// Load grammars for all supported languages SEQUENTIALLY.
131+
// web-tree-sitter ≤0.24.x has a race condition when loading multiple
132+
// WASM grammars concurrently via Promise.all() — the Emscripten glue
133+
// code shares global state during instantiation, causing cross-language
134+
// symbol contamination (e.g., "bad export type for
135+
// 'tree_sitter_javascript_external_scanner_create': undefined").
136+
// This manifests on Node.js ≤20 but not on Node.js ≥22 due to
137+
// differences in V8's WebAssembly.instantiate isolation.
138+
// See: https://github.com/nicolo-ribaudo/tree-sitter/nicolo-ribaudo/tree-sitter/issues/5172
131139
const languages = Object.keys(GRAMMAR_FILES) as SupportedLanguage[];
132-
const loadPromises = languages.map(async (lang) => {
140+
const errors: Array<{ lang: SupportedLanguage; error: Error }> = [];
141+
for (const lang of languages) {
133142
const grammarFile = GRAMMAR_FILES[lang];
134-
const grammarPath = resolveGrammarPath(grammarFile);
135-
const language = await Parser.Language.load(grammarPath);
136-
this.languages.set(lang, language);
137-
});
138-
139-
await Promise.all(loadPromises);
143+
try {
144+
const grammarPath = resolveGrammarPath(grammarFile);
145+
const language = await Parser.Language.load(grammarPath);
146+
this.languages.set(lang, language);
147+
} catch (err) {
148+
// Non-fatal: log and continue so other languages still work.
149+
// The grammar file may be missing or ABI-incompatible.
150+
errors.push({ lang, error: err as Error });
151+
}
152+
}
153+
if (errors.length > 0 && this.languages.size === 0) {
154+
// All grammars failed — this is fatal.
155+
const msgs = errors.map(e => ` ${e.lang}: ${e.error.message}`).join('\n');
156+
throw new Error(`Failed to load any tree-sitter grammars:\n${msgs}`);
157+
}
140158
this._initialized = true;
141159
}
142160

packages/mcp-server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"homepage": "https://codes.evallab.ai",
4242
"dependencies": {
4343
"@modelcontextprotocol/sdk": "^1.12.1",
44-
"@opencodereview/core": "^2.1.1",
44+
"@opencodereview/core": "workspace:*",
4545
"zod": "^3.24.0"
4646
},
4747
"devDependencies": {

pnpm-lock.yaml

Lines changed: 4 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)