Skip to content

fix(host-daemon): avoid stack overflow listing large directory trees - #2363

Open
yazydzhi wants to merge 1 commit into
get-bb:mainfrom
yazydzhi:fix/file-list-recursive-push-stack-overflow
Open

fix(host-daemon): avoid stack overflow listing large directory trees#2363
yazydzhi wants to merge 1 commit into
get-bb:mainfrom
yazydzhi:fix/file-list-recursive-push-stack-overflow

Conversation

@yazydzhi

Copy link
Copy Markdown

Fixes #2362.

Problem

`listPathsRecursively` in `apps/host-daemon/src/command-handlers/file-list.ts` merges each subdirectory's results with:

```ts
results.push(...(await listPathsRecursively({ ...args, dir: fullPath })));
```

`Array.prototype.push(...arr)` spreads every element as a call argument. Once an accumulated subtree crosses V8's argument-count ceiling (~100k, engine-dependent), this throws `RangeError: Maximum call stack size exceeded` instead of returning. Any caller of file listing/search (a plugin's `listTree`, project file search, etc.) on a large enough workspace — a big Obsidian vault, a large monorepo — sees this surface as an opaque `HTTP 502`.

Fix

Replace the spread-push with a plain loop, which has no argument-count limit:

```ts
const childResults = await listPathsRecursively({ ...args, dir: fullPath });
for (const childResult of childResults) results.push(childResult);
```

Testing

Added a regression test that creates a 150k-file subtree and asserts `listPathsRecursively` returns instead of throwing.

  • Confirmed the new test reproduces the exact `RangeError: Maximum call stack size exceeded` against the pre-fix code (stashed the fix, ran the test, same error/stack as reported).
  • With the fix applied, all 15 tests in `file-list.test.ts` pass (`vitest run --config vitest.config.ts` in `apps/host-daemon`).

Test plan

  • `vitest run` in `apps/host-daemon` — 15/15 passing
  • Verified the new test fails with the exact reported error on the pre-fix code

listPathsRecursively merged each subdirectory's results with
results.push(...childResults). Array.push spreads its arguments onto
the call stack, so a subtree with enough entries (~100k+ depending on
the engine) throws "RangeError: Maximum call stack size exceeded"
instead of returning. This broke file listing/search entirely for
large workspaces (e.g. a big Obsidian vault with tens of thousands of
files), surfacing as an opaque HTTP 502 from any plugin or route that
calls files.listPaths/listTree.

Replace the spread-push with a plain loop, which has no argument-count
limit. Added a regression test that recreates a 150k-file subtree and
asserts listPathsRecursively returns instead of throwing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File listing crashes with 502 on large workspaces (Maximum call stack size exceeded)

1 participant