You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: code-interpreter-js readLines is O(n²) on long output lines and blocks the event loop #1990
N/A (client-side SDK bug, not specific to one sandbox)
Environment
@e2b/code-interpreter 2.6.0 in production; also reproduced against packages/code-interpreter-js/src/utils.ts on main (2.9.0). Node 22.
Timestamp of the issue
2026-10-09 22:25 UTC (first seen in production; reproducible at any time)
Frequency
Happens every time
Expected behavior
runCode takes time proportional to output size, so a long single-line output (base64 image, wide DataFrame, large JSON) doesn't block the caller's event loop.
Actual behavior
readLines appends each chunk to the buffer (buffer += decoder.decode(...)) and then searches the whole buffer with buffer.indexOf('\n'). When a line has no newline, V8 has to rebuild the entire buffer into one string on every chunk, so the total cost grows with the square of the line length. All of that runs synchronously on the caller's main thread. In production, a single cell printing one ~40 MB line stalled our Node process's event loop for several seconds and added about 2 GB of memory.
Issue reproduction
Copy readLines from utils.ts and feed it one newline-free line in 16 KB chunks:
This is e2b-dev/code-interpreter#251 (ENG-3808). That issue got stranded when the SDK moved into this monorepo in #1768, and the fix PR there (e2b-dev/code-interpreter#308) now conflicts with a deleted file. #1946 fixed UTF-8 decoding across chunks but kept the quadratic buffering. The fix proposed in #251 should work: search only the new chunk for \n, keep the partial pieces in an array, and join once per complete line. It also needs to keep #1946's streaming TextDecoder. We're running a patch like this on 2.6.0, and it handles 40 MB single-line output without stalling.
I'd like to take this one. The O(n²) in readLines looks like a bounded fix (decode only the new chunk, search for \n in the new chunk, accumulate line fragments and join once per line). I'll reproduce with a benchmark first, fix JS + the equivalent Python sync/async paths, and open a PR with before/after numbers. Thanks for the detailed report!
Fix PR opened: #1991 — now scans only the newly arrived chunk instead of re-scanning the whole buffer, making it linear on long single-line outputs (40MB line: ~9s → ~0.1s). 15 new regression tests pass.
Activity
devin-ai-integration commentedon Oct 15, 2026
Triage
readLinesstream line splitting used byrunCode)readLinesinpackages/code-interpreter-js/src/utils.tsappends every chunk to one string buffer and then searches the whole buffer for\n, so time grows with the square of the line length and very long single-line outputs (e.g. ~40 MB) block the Node event loop. The fix should search only the new chunk, keep partial pieces in an array, join once per line, and keep the streamingTextDecoderfrom fix(code-interpreter): preserve UTF-8 across response chunks #1946. This is the fix proposed in O(n²) string concatenation in readLines causes OOM on large stdout (>1 MB) code-interpreter#251 / ENG-3808.Written by Devin
Kylinny commentedon Oct 15, 2026
I'd like to take this one. The O(n²) in
readLineslooks like a bounded fix (decode only the new chunk, search for\nin the new chunk, accumulate line fragments and join once per line). I'll reproduce with a benchmark first, fix JS + the equivalent Python sync/async paths, and open a PR with before/after numbers. Thanks for the detailed report!Kylinny commentedon Oct 15, 2026
Fix PR opened: #1991 — now scans only the newly arrived chunk instead of re-scanning the whole buffer, making it linear on long single-line outputs (40MB line: ~9s → ~0.1s). 15 new regression tests pass.