Skip to content

FileSearch.initializeFileSearchState() walks and indexes the entire workspace unbounded — kills the renderer on Remote-SSH #13249

Description

@Fabian188

Before submitting your bug report

Relevant environment info

- OS: macOS
- Continue version: Continue 2.0.0 (VS Code, darwin-arm64), reproduced against current `main`
- IDE version: VS Code 1.10x, macOS 26.5.2, Apple M5 Pro
- Model:
- config:
  

  
  OR link to agent in Continue hub:

Description

I'm a human and had several crashes with VC when working remotely and I spend a lot of Claude tokens to identify the issue. The following report ist from Claude Opus 5

Environment

  • Continue 2.0.0 (VS Code, darwin-arm64), reproduced against current main
  • VS Code 1.10x, macOS 26.5.2, Apple M5 Pro
  • Remote-SSH workspace, ~120k directories / ~1.08M non-ignored files

Summary

On every activation, FileSearch walks the whole workspace and indexes every path
into MiniSearch in one synchronous addAll(). On a large Remote-SSH workspace this
blocks the local extension host for 20–27 s. Because Remote-SSH runs its tunnel in
that same extension host, the connection to the remote dies, VS Code enters a
reconnect loop it cannot complete, and the renderer process is SIGKILLed by the
kernel
for exhausting its Mach port table. I lost my window roughly every 35
minutes for three days before tracking this down.

Root cause

extensions/vscode/src/util/FileSearch.ts:

constructor(ide) { this.ide = ide; this.initializeFileSearchState(); }  // not awaited

private async initializeFileSearchState() {
  const results = await walkDirs(this.ide, { source: "file search initialization" });
  this.miniSearch.addAll(results.flat().map((uri) => ({
    id: uri, relativePath: vscode.workspace.asRelativePath(uri) })));
}

Three problems compound:

  1. No cap on the number of files.
  2. addAll() is synchronous — no chunking, no yielding to the event loop.
    With a custom tokenize (default tokenizer + splitCamelCaseAndNonAlphaNumeric,
    then deduplicateArray) this is expensive per document.
  3. No special case for remote workspaces, where every readDirectory in the DFS
    walker is an RPC relayed through the renderer to the remote host. The extension is
    extensionKind: ["ui","workspace"], so it runs locally even for remote workspaces.

The default ignore list (build/ out/ bin/ dist/ target/ node_modules/ …) does not
match common out-of-source build trees such as debug/, release/, release_gcc9/,
so those get walked in full even though the resulting *.o/*.a files are then
discarded by the filetype filter — the directory traversal cost is paid regardless.

Evidence

Five CPU profiles captured automatically by VS Code's own "UNRESPONSIVE extension
host" profiler, from five separate crashes, all show the same thing (self time):

1.913s 35.9%  createPath                @ MiniSearch
1.547s 29.0%  initializeFileSearchState
0.764s 14.3%  add                       @ MiniSearch
0.252s  4.7%  splitCamelCaseAndNonAlphaNumeric
...                                     ≈ 86–93% total

Extension host log — a resolveAuthority request sent by the renderer at 18:14:41
is not picked up until 18:15:05, i.e. after the renderer has already been killed:

18:14:41  renderer: Invoking resolveAuthority(ssh-remote)...    (renderer.log)
18:14:41  renderer: Extension host (LocalProcess) is unresponsive.
18:14:42  renderer: UNRESPONSIVE extension host: starting to profile NOW
18:14:47  renderer: 'continue.continue' took 96.7% of 4840ms
18:15:01  kernel:   Code Helper (Ren[17217] caught allocating too many mach ports.
                    Num of ports allocated 267842
18:15:05  exthost:  [resolveAuthority(ssh-remote,2)][0ms] activating remote resolvers
18:15:06  exthost:  Extension host terminating: renderer closed the MessagePort

Same signature in 4/4 logged crashes (blocked 18 s, 20 s, 24 s), and the profile
timestamps line up with further window restarts going back several days.

Renderer Mach port count, sampled every second:

18:12:41 … 18:14:37     333   (flat for hours)
18:14:40                369   ← reconnect begins
18:14:58             66 417
18:15:01            267 842   ← EXC_GUARD, SIGKILL

Nothing is written to the crash reporter: EXC_GUARD kills leave no crash dialog and
no renderer log, which is why this is so hard to attribute.

Impact beyond the crash

The persistent codebase index never gets anywhere. After six weeks:

tag_catalog     0 rows
global_cache    0 rows
indexing_lock   1 row, id=142   ← the 142nd attempt

Each attempt takes the lock, walks, gets killed, and starts over. The MiniSearch
index itself is in-memory only and holds paths, not content — so ~1.08M paths were
re-walked over the remote connection and thrown away once per window, for an
@file completion that had not been used since installation.

Suggested fixes

  • Cap the number of indexed files (e.g. 50k) and log when the cap is hit.
  • Chunk addAll and await between batches so the event loop stays responsive.
  • For vscode-remote:// workspaces, use vscode.workspace.findFiles() — it runs in
    the remote file system provider — or skip the eager walk entirely and build the
    index lazily on first use.
  • Consider adding common out-of-source build directory names to the default ignores,
    and pruning a directory before descending when everything under it is filtered.

Related

To reproduce

No response

Log output

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions