← Files Compound EngineeringARCHIVED FILE

docs/solutions/developer-experience/global-fsmonitor-makes-the-suite-slow-and-flaky.md

3.65 KB · Oct 2, 2026 · 00:33 UTC

↓ Download file

---
title: "A global core.fsmonitor=true makes the subprocess-heavy suite 2.6x slower and flaky"
date: 2026-09-08
category: developer-experience
module: test-suite
problem_type: test_failure
component: testing_framework
symptoms:
  - "bun run test finishes in 220s instead of ~85s and 2-5 tests time out at 20000ms on every run"
  - "The timed-out tests differ from run to run and pass in isolation in under a second"
  - "The log shows 'killed 1 dangling process' before a beforeEach hook timeout that ran git commit"
root_cause: config_error
resolution_type: environment_setup
severity: medium
tags:
  - git
  - fsmonitor
  - flaky-tests
  - cursor-cloud-agent
  - test-timeouts
---

# A global core.fsmonitor=true makes the subprocess-heavy suite 2.6x slower and flaky

## Problem

On a Cursor cloud-agent VM, `bun run test` ran in 220s with two to five 20s timeouts on every run, each time in a different git-heavy file (`cli.test.ts`, `codex-dev.test.ts`, `ce-code-review-mechanics.test.ts`, `doc-claims-validator.test.ts`). Every timed-out file passed in isolation in seconds, so the failures looked like ordinary 4-core load flakiness and were about to be written off as such.

## Symptoms

- Suite wall time 216-244s on a 4-core VM versus ~81s on CI's 4-core runner.
- A rotating set of timeouts: `CLI > install --branch clones a specific branch`, `Codex development installation transitions > ...`, `scope helper excludes base-only changes after the base advances`.
- `killed 1 dangling process` printed before a `beforeEach` hook timeout whose body was `git commit`.

## What Didn't Work

- Rerunning the timed-out files in isolation: they passed, which hides the cause rather than finding it.
- Attributing it to CPU contention alone: the suite is idle-bound (blocked on `git`, `python3`, `bash`), so contention should not have turned a 3s file into a 20s timeout.

## Solution

The VM's global git config (`git config --global --list`) carried `core.fsmonitor=true`. The suite creates hundreds of throwaway repos with `git init`, and with that setting every first `git` command in a fresh repo starts an fsmonitor daemon; the daemons pile up, some `git commit`/`git status` calls block on them, and Bun eventually kills the dangling processes.

Running the suite with a minimal global config that keeps the identity and drops the setting made it green and fast on the same tree:

```bash
printf '[user]\n\tname = Cursor Agent\n\temail = cursoragent@cursor.com\n' > /tmp/min-gitconfig
GIT_CONFIG_GLOBAL=/tmp/min-gitconfig bun run test
# 3941 pass / 0 fail in 83.7s, versus 220s and 5 timeouts with the VM's default config
```

Per-file confirmation: `tests/codex-dev.test.ts` took 30s with one timeout under the VM config and 266ms with the minimal one.

## Why This Works

fsmonitor is a per-repository watcher meant for one long-lived checkout. A test suite that mass-produces short-lived repos turns it into a daemon per repo, and the daemons' startup and IPC dominate the git calls the tests are blocked on. Removing the setting restores git to the plain stat-based path the suite was measured against.

## Prevention

- Before blaming load for git-test timeouts, check `git config --global --get core.fsmonitor`; a `true` there explains a rotating set of timeouts in git-heavy files.
- When running the suite inside a Cursor cloud agent, pass `GIT_CONFIG_GLOBAL` pointing at a minimal config as above, or run `git config --global --unset core.fsmonitor` for the session. CI runners do not carry the setting, so CI results were never affected.

## Related Issues

- Measured while dogfooding PR #1656 (Compound Packs merged with main); every suite run before the fix reported "load-induced" timeouts that were actually this.

SHA-256: 98e68de41970072e83db8918984eac2d961b3ca36f25849e225da6fbc6025e42