[GH-ISSUE #7115] [Bug] JavaScript analysis time doubles per || operand in 6.8.0; a 24-call chain (CodeMirror 5 pug mode) exhausts the 300 s per-source deadline #4276

Closed
opened 2026-10-31 00:48:25 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @kaoru0822-kitauji on GitHub (Oct 25, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7115

Originally assigned to: @kaoru0822-kitauji on GitHub.

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

In 6.8.0, JavaScript source analysis time doubles with each extra operand of a || chain. One expression with about 24 or more short-circuit calls exhausts the default 300 s per-source deadline (provider_timeout). 6.7.0 analyzes the same files in about 1.5 s regardless of chain length.

Synthetic file index.js, where n is the number of || operands:

function next(s) {
  var tok = f0(s) || f1(s) || f2(s) /* … */ || f23(s);
  return tok;
}
module.exports = next;

rea analyze-javascript-application <dir> --analysis-timeout-ms 60000 --format json, with the directory holding only index.js and a minimal package.json. Wall time, one run each:

n 6.7.0 6.8.0
18 — 2.3 s
20 — 4.9 s
21 1.5 s 7.8 s
22 1.5 s 16.1 s
23 1.4 s 26.0 s
24 1.7 s 55.9 s

Peak RSS stays around 390–410 MB. The time is CPU in the owned analyzer worker, which sits at about 100% CPU throughout.

Real-world trigger: CodeMirror 5's pug mode. Its nextToken is a 38-operand || chain (codemirror@5.65.18, mode/pug/pug.js lines 537–580).

Input 6.7.0 6.8.0
codemirror@5.65.18 mode/pug/pug.js (15,991 B), unmodified 1.75 s, ok provider_timeout at 60 s
Obsidian 1.12.7 obsidian.asar → lib/codemirror/modes.min.js (562,656 B, all CodeMirror 5 modes minified), alone 7.6 s, ok provider_timeout at 300 s
Obsidian 1.12.7 obsidian.asar, whole archive times out later, on file 25/36 times out on file 11/36 (modes.min.js)

Bisecting modes.min.js by top-level statement isolates the pug mode (7,681 B); nothing else in the file is slow. Within pug.js, keeping only the module header and nextToken still times out, while every other function analyzes in under 2 s.

Reproduction

mkdir -p /tmp/or24 && cd /tmp/or24
node -e 'const n=24;console.log(`function next(s) {\n  var tok = ${Array.from({length:n},(_,i)=>`f${i}(s)`).join(" || ")};\n  return tok;\n}\nmodule.exports = next;`)' > index.js
echo '{"name":"or","version":"1.0.0","main":"index.js"}' > package.json
time npx -y rea-agents@6.7.0 analyze-javascript-application /tmp/or24 --format json > /dev/null   # ~1.7 s
time npx -y rea-agents@6.8.0 analyze-javascript-application /tmp/or24 --format json > /dev/null   # ~56 s; n=25 roughly doubles it

Expected behavior

Analysis cost should grow roughly linearly with the length of a logical-expression chain, as in 6.7.0. Long ||/&& dispatch chains are common in hand-written tokenizers and minified code.

Impact and scope

Any JavaScript or Electron application that bundles code like this, including every application that ships the CodeMirror 5 mode bundle, loses that source to provider_timeout. The full per-source budget is spent first: 5 minutes by default, with one CPU core pinned. Both the CLI and MCP analyze_javascript_application are affected (MCP was not timed separately). I did not test whether && or ?? chains behave the same way.

REA version

6.8.0 (regression from 6.7.0)

Runtime and platform

macOS 26.7.1 (25G241) arm64, Node.js 24.22.1. Another agent session's analysis jobs were running on the same 10-core host, so absolute times are noisy, but the doubling is consistent across runs.

Target and artifact context

Synthetic file above. Public codemirror@5.65.18 mode/pug/pug.js. Obsidian 1.12.7 obsidian.asar (24,060,763 B).

Interface

CLI (the MCP tool shares the analyzer)

Earliest failure stage

JavaScript source analysis (owned analyzer worker)

Relevant output or evidence

{"error":"JavaScript application analysis failed","code":"provider_timeout","category":"timeout","message":"JavaScript source analysis reached its 300000ms per-source server/provider deadline (analysis_timeout_ms), not the MCP client deadline."}

Typed outcome or recovery expected

The typed provider_timeout with partial Evidence is correct for a genuine deadline. The problem is that this input should not reach the deadline.

Analysis or suspected cause

Source-derived hypothesis, not verified: the 2^n growth suggests a 6.8.0 analysis pass enumerates every short-circuit path or value combination of a logical expression, for example the new assignment-value-to-write linking or the value/effect propagation added in this release, instead of merging the operands.

Additional context

Possibly related, but a different symptom: #6344 (heap exhaustion on a react-dom chunk, also present in 6.7.0). #746 covered the earlier silent failure on the same Obsidian archive.

Originally created by @kaoru0822-kitauji on GitHub (Oct 25, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7115 Originally assigned to: @kaoru0822-kitauji on GitHub. ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior In 6.8.0, JavaScript source analysis time doubles with each extra operand of a `||` chain. One expression with about 24 or more short-circuit calls exhausts the default 300 s per-source deadline (`provider_timeout`). 6.7.0 analyzes the same files in about 1.5 s regardless of chain length. Synthetic file `index.js`, where `n` is the number of `||` operands: ```js function next(s) { var tok = f0(s) || f1(s) || f2(s) /* … */ || f23(s); return tok; } module.exports = next; ``` `rea analyze-javascript-application <dir> --analysis-timeout-ms 60000 --format json`, with the directory holding only `index.js` and a minimal `package.json`. Wall time, one run each: | n | 6.7.0 | 6.8.0 | |---|---|---| | 18 | — | 2.3 s | | 20 | — | 4.9 s | | 21 | 1.5 s | 7.8 s | | 22 | 1.5 s | 16.1 s | | 23 | 1.4 s | 26.0 s | | 24 | 1.7 s | 55.9 s | Peak RSS stays around 390–410 MB. The time is CPU in the owned analyzer worker, which sits at about 100% CPU throughout. Real-world trigger: CodeMirror 5's `pug` mode. Its `nextToken` is a 38-operand `||` chain (`codemirror@5.65.18`, `mode/pug/pug.js` lines 537–580). | Input | 6.7.0 | 6.8.0 | |---|---|---| | `codemirror@5.65.18` `mode/pug/pug.js` (15,991 B), unmodified | 1.75 s, ok | `provider_timeout` at 60 s | | Obsidian 1.12.7 `obsidian.asar` → `lib/codemirror/modes.min.js` (562,656 B, all CodeMirror 5 modes minified), alone | 7.6 s, ok | `provider_timeout` at 300 s | | Obsidian 1.12.7 `obsidian.asar`, whole archive | times out later, on file 25/36 | times out on file 11/36 (`modes.min.js`) | Bisecting `modes.min.js` by top-level statement isolates the `pug` mode (7,681 B); nothing else in the file is slow. Within `pug.js`, keeping only the module header and `nextToken` still times out, while every other function analyzes in under 2 s. ### Reproduction ```sh mkdir -p /tmp/or24 && cd /tmp/or24 node -e 'const n=24;console.log(`function next(s) {\n var tok = ${Array.from({length:n},(_,i)=>`f${i}(s)`).join(" || ")};\n return tok;\n}\nmodule.exports = next;`)' > index.js echo '{"name":"or","version":"1.0.0","main":"index.js"}' > package.json time npx -y rea-agents@6.7.0 analyze-javascript-application /tmp/or24 --format json > /dev/null # ~1.7 s time npx -y rea-agents@6.8.0 analyze-javascript-application /tmp/or24 --format json > /dev/null # ~56 s; n=25 roughly doubles it ``` ### Expected behavior Analysis cost should grow roughly linearly with the length of a logical-expression chain, as in 6.7.0. Long `||`/`&&` dispatch chains are common in hand-written tokenizers and minified code. ### Impact and scope Any JavaScript or Electron application that bundles code like this, including every application that ships the CodeMirror 5 mode bundle, loses that source to `provider_timeout`. The full per-source budget is spent first: 5 minutes by default, with one CPU core pinned. Both the CLI and MCP `analyze_javascript_application` are affected (MCP was not timed separately). I did not test whether `&&` or `??` chains behave the same way. ### REA version 6.8.0 (regression from 6.7.0) ### Runtime and platform macOS 26.7.1 (25G241) arm64, Node.js 24.22.1. Another agent session's analysis jobs were running on the same 10-core host, so absolute times are noisy, but the doubling is consistent across runs. ### Target and artifact context Synthetic file above. Public `codemirror@5.65.18` `mode/pug/pug.js`. Obsidian 1.12.7 `obsidian.asar` (24,060,763 B). ### Interface CLI (the MCP tool shares the analyzer) ### Earliest failure stage JavaScript source analysis (owned analyzer worker) ### Relevant output or evidence ```json {"error":"JavaScript application analysis failed","code":"provider_timeout","category":"timeout","message":"JavaScript source analysis reached its 300000ms per-source server/provider deadline (analysis_timeout_ms), not the MCP client deadline."} ``` ### Typed outcome or recovery expected The typed `provider_timeout` with partial Evidence is correct for a genuine deadline. The problem is that this input should not reach the deadline. ### Analysis or suspected cause Source-derived hypothesis, not verified: the 2^n growth suggests a 6.8.0 analysis pass enumerates every short-circuit path or value combination of a logical expression, for example the new assignment-value-to-write linking or the value/effect propagation added in this release, instead of merging the operands. ### Additional context Possibly related, but a different symptom: #6344 (heap exhaustion on a react-dom chunk, also present in 6.7.0). #746 covered the earlier silent failure on the same Obsidian archive.
bsakaguchi 2026-10-31 00:48:25 +00:00
Author
Owner

@XinwangTao commented on GitHub (Oct 25, 2026):

这个复现非常干净,感谢提供。2^n 的增长曲线基本坐实了 6.8.0 在逻辑表达式上走了短路路径/值组合枚举而不是合并——|| 链 n 个 operand 的短路路径天然是 2^n 量级,正好解释从 21 个 operand 的 1.5s 跳到 24 个的 55.9s。建议分析器对 logical expression 改为合并抽象:把整条 ||/&& 链当作一个整体做值集合的定点合并而不是全路径展开;或至少对链长超过阈值的表达式降级为线性扫描路径,避免真实 tokenizer(CodeMirror 5 pug 的 38-operand nextToken)直接耗尽 provider_timeout。也建议把 or24 合成用例和 pug.js 加进回归测试,防止同类路径枚举回归再次混入。

<!-- gh-comment-id:6396441572 --> @XinwangTao commented on GitHub (Oct 25, 2026): 这个复现非常干净,感谢提供。2^n 的增长曲线基本坐实了 6.8.0 在逻辑表达式上走了短路路径/值组合枚举而不是合并——|| 链 n 个 operand 的短路路径天然是 2^n 量级,正好解释从 21 个 operand 的 1.5s 跳到 24 个的 55.9s。建议分析器对 logical expression 改为合并抽象:把整条 ||/&& 链当作一个整体做值集合的定点合并而不是全路径展开;或至少对链长超过阈值的表达式降级为线性扫描路径,避免真实 tokenizer(CodeMirror 5 pug 的 38-operand nextToken)直接耗尽 provider_timeout。也建议把 or24 合成用例和 pug.js 加进回归测试,防止同类路径枚举回归再次混入。
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4276
No description provided.