Skip to content

VS Code Codex extension can allocate about 1M inotify watches on Linux large workspace #23574

Open

Description

@interconnectedMe

What version of the IDE extension are you using?

openai.chatgpt-26.513.21555-linux-x64

What subscription do you have?

ChatGPT Pro

Which IDE are you using?

VS Code 1.120.0

What platform is your computer?

Linux 6.17.0-29-generic x86_64 x86_64

What issue are you seeing?

On Linux, the VS Code Codex extension can drive the user session close to or beyond the inotify watch limit in a large workspace. The high watch count is owned by the VS Code extension host process, not by VS Code's normal file watcher and not by the Codex app-server child.

Observed measurements:

openai.chatgpt disabled in the VS Code Planning profile: about 80k-90k total watches
openai.chatgpt enabled and Codex chats opened/resumed: about 1,048k to 1,234k total watches
VS Code extension host process during bad state: about 900k-1,151k watches
normal VS Code file-watcher process during bad state: about 3k-79k watches
Codex app-server child during bad state: about 213 watches

The impact was desktop-wide inotify exhaustion: logs showed ENOSPC, No space left on device, and OS file watch limit reached, with collateral failures in the Linux desktop session.

Relevant Codex log excerpts from the bad state:

Features enabled ... workspace_dependencies ...
[git-repo-watcher] Starting git repo watcher
codex_file_watcher: failed to watch /etc: OS file watch limit reached
codex_file_watcher: failed to watch /media/S_Drive/projects/strategy-tester/.agents/skills: OS file watch limit reached
codex_app_server_transport::transport: dropping overload response ... outbound queue is full
[git-repo-watcher] Git repo watcher failed ... ENOSPC ... watch '/media/S_Drive/projects/strategy-tester/.git/objects/...'

This workspace has large generated/runtime trees, but they are excluded from VS Code's normal watcher:

"files.watcherExclude": {
  "**/.sandcastle/worktrees/**": true,
  "**/data/**": true,
  "**/logs/**": true
}

The normal VS Code file watcher stayed low, which suggests the Codex extension-side watcher path is bypassing VS Code's files.watcherExclude and/or recursively watching too much Git/workspace state.

What steps can reproduce the bug?

  1. On Linux, open a large VS Code workspace with the Codex extension enabled.
  2. Use a workspace with large generated/runtime directories under the repo root. In my case, before local mitigation:
repo total:              about 1,071,929 files
logs/:                   about   716,933 files
data/:                   about   129,956 files
.sandcastle/worktrees/:  about   102,877 files
  1. Configure VS Code workspace excludes for those large directories, for example:
"files.watcherExclude": {
  "**/.sandcastle/worktrees/**": true,
  "**/data/**": true,
  "**/logs/**": true
}
  1. Start or resume Codex chats in the VS Code Codex panel. A focused repro opened one existing Codex chat, then opened about 3-4 additional Codex chats.
  2. Monitor inotify watches:
sudo bash -c 'total=0; for f in /proc/[0-9]*/fdinfo/*; do n=$(grep -c "inotify wd:" "$f" 2>/dev/null || true); total=$((total+n)); done; echo "$total"'

for pid in $(find /proc/*/fd -lname anon_inode:inotify 2>/dev/null | sed 's#/proc/##; s#/fd/.*##' | sort -u); do
  watches=$(grep -h "inotify wd:" /proc/$pid/fdinfo/* 2>/dev/null | wc -l)
  comm=$(cat /proc/$pid/comm 2>/dev/null)
  cmdline=$(tr "\0" " " < /proc/$pid/cmdline 2>/dev/null | cut -c1-220)
  printf '%8s %7s %-18s %s\n' "$watches" "$pid" "$comm" "$cmdline"
done | sort -nr | head -20

Observed focused repro:

10:08:58 total_watches=83,205
10:10:08 total_watches=83,205
10:11:18 total_watches=1,234,730
10:12:37 total_watches=1,234,736
10:13:55 total_watches=1,234,736
11:02:12 total_watches=1,234,754

The watches did not release after closing the extra Codex chat tabs/panels, and they remained after about 30 minutes. Developer: Reload Window briefly dropped the count, but the extension restarted and re-triggered the high watcher state.

Disabling workspace_dependencies through the bundled Codex CLI did not prevent this extension-side watcher path. The CLI reported the feature as disabled, but after VS Code reload the extension log still listed workspace_dependencies, started [git-repo-watcher], and the extension host climbed back to about 1.23M total watches.

What is the expected behavior?

The Codex VS Code extension should not recursively allocate hundreds of thousands or more than one million inotify watches in the extension host for a workspace where VS Code's own file watcher is correctly constrained by files.watcherExclude.

Expected behavior:

  • Respect VS Code workspace watcher excludes or apply equivalent filtering before recursive extension-side watching.
  • Avoid recursively watching .git/objects and large generated/runtime directories.
  • Bound watcher allocation and degrade gracefully if a workspace is too large.
  • Release extension-created watches when Codex chat tabs/panels are closed or when the triggering state ends.
  • Avoid desktop-wide ENOSPC/inotify exhaustion.

Additional information

The strongest isolation signal is process ownership:

normal VS Code file watcher: low watch count
Codex app-server child: about 213 watches
VS Code extension host: about 1,151,500 watches

A local mitigation confirmed that real workspace tree size drives the spike. Moving logs/ outside the real workspace tree and symlinking it back removed about 731k watches:

Before: Codex extension host about 1,151,522 watches
After moving logs/ out of the real tree: Codex extension host about 420,306 watches

That mitigation is only a workaround. It also shows that the extension host appears to expand the real filesystem tree under the workspace root instead of honoring the configured VS Code watcher excludes.

Closest related issue I found: #23191 reports the same general git-repo-watcher/ENOSPC family in Cursor Remote SSH when $HOME accidentally becomes a large Git repo. This issue is separate because it reproduces in VS Code with an intended repo workspace, measured extension-host watch ownership, and normal VS Code watcher excludes already in place.

Adjacent but not identical: #22421, #17394, #20295.

Activity

  1. github-actions commented on May 19, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  2. crystal150 commented on Jun 22, 2026

    @crystal150

    I can reproduce the same watcher-exhaustion class on a newer Codex VS Code extension build. Sharing sanitized measurements in case they help with prioritization and fixing the extension-side watcher path.

    Environment:

    • IDE: VS Code Remote SSH, VS Code 1.125.1
    • OS: Ubuntu 22.04.5 LTS, Linux 5.15 x86_64
    • Codex IDE extension: openai.chatgpt-26.616.51431-linux-x64
    • Current inotify limits after local mitigation: fs.inotify.max_user_watches=1048576, fs.inotify.max_user_instances=2048

    Current process attribution after a full VS Code restart and local cleanup:

    VS Code extensionHost:        357,182 inotify watches
    VS Code fileWatcher process:   14,455 inotify watches
    Codex app-server child:         1,650 inotify watches
    total user watches:           382,095
    

    Most of the extensionHost watches map back to ignored/generated workspace trees:

    node_modules:                    253,381
    apps/mobile/build:                32,233
    .claude/worktrees:                19,061
    other workspace files:            17,106
    .agents/skills/.../.local:        11,230
    .git:                              7,923
    .local:                            7,400
    apps/web/.next:                    4,764
    .playwright-cli:                   4,081
    

    Those high-churn/generated directories are already excluded from VS Code's normal watcher/search configuration, and the normal VS Code fileWatcher process remains comparatively small. The large count is owned by the extension host, which makes this look like the Codex extension-side watcher is still recursively watching large workspace subtrees instead of honoring VS Code files.watcherExclude / equivalent ignore rules before allocating watches.

    Impact observed before mitigation:

    • Remote Extension Host logs showed ENOSPC: System limit for number of file watchers reached.
    • VS Code became unstable/hung when Codex IDE extension was active alongside another AI coding extension.
    • The other extension was not the main watcher owner in the measured state; Codex/VS Code extensionHost dominated the inotify count.
    • Raising the OS inotify limit and killing a stale extensionHost process made the workspace usable again, but that is only a workaround.

    Expected behavior / likely useful fixes:

    • Honor VS Code files.watcherExclude and/or .gitignore for the extension-side recursive watcher before watch allocation.
    • Add an extension-specific watcher exclude setting if the watcher cannot rely on VS Code settings.
    • Avoid watching generated dependency/build trees like node_modules, .next, mobile build outputs, local cache/artifact folders, and nested worktrees by default.
    • Bound watcher allocation and degrade gracefully before exhausting the user's inotify budget.

    No private logs attached here; the data above is sanitized process/count attribution only.

  3. pinelibg commented on Jun 22, 2026

    @pinelibg

    I can also reproduce this on openai.chatgpt-26.616.51431-linux-x64.

    In my case, the large generated tree was cdk.out. It had grown very large and contained many build asset files.

    Environment:

    • VS Code Server: 1.125.1
    • Codex extension: openai.chatgpt-26.616.51431-linux-x64
    • OS: Ubuntu 24.04 x86_64
    • Effective sysctl value: fs.inotify.max_user_watches = 524288
    • Workspace: large monorepo with very large generated cdk.out

    VS Code had files.watcherExclude configured for **/cdk.out/**.

    Codex investigated /proc/<pid>/fdinfo and mapped the inotify inode values back to workspace-relative paths.

    With the Codex VS Code extension enabled:

    • VS Code extensionHost: 508,479 watches
    • VS Code fileWatcher: 15,623 watches
    • Of the extensionHost watches, 501,622 mapped to cdk.out
    • The normal VS Code fileWatcher had 0 watches for cdk.out, so the VS Code watcher exclude was effective there

    After disabling the Codex VS Code extension and reloading:

    • VS Code extensionHost dropped from 508,479 watches to 1 watch
    • VS Code fileWatcher remained around 15,623 watches

    Temporarily, disabling the Codex VS Code extension is currently an effective workaround for my environment.

  4. liuminsheng3 commented on Jun 22, 2026

    @liuminsheng3

    I would add a regression test that treats this as an inotify budget failure, not a normal disk-byte ENOSPC.

    A useful fixture would be a repo with generated/runtime trees that are explicitly excluded before Codex allocates any extension-side watchers:

    • node_modules/
    • .next/, dist/, build/, cdk.out/
    • logs/, data/, coverage/
    • .claude/worktrees/, .sandcastle/worktrees/, other agent worktrees
    • nested .git/objects/

    Then the test can open/resume a Codex chat in VS Code and assert three things from /proc/<pid>/fdinfo attribution:

    1. the VS Code extension host stays under a hard watcher budget, e.g. min(50_000, max_user_watches * 0.15), or enters degraded mode before allocation
    2. excluded/generated paths contribute zero or near-zero extension-created watches
    3. closing Codex panels/chats or reloading the window releases extension-created watches instead of leaving a long-lived high count

    The process split reported above is the strongest signal to preserve in the test: VS Code's normal file watcher is small, the Codex app-server child is small, and the extension host owns the large watch count. That should fail the test even if the machine has a high sysctl limit.

    For the user-facing behavior, I would also avoid surfacing this as generic "No space left on device". Something like "inotify watch budget exhausted; generated directories may be watched despite excludes" would keep users from deleting source or Git state when the real issue is watch allocation.

    Temporary workaround hierarchy, from least risky to most masking:

    • disable the Codex VS Code extension for that workspace
    • move very large generated trees outside the real workspace and symlink them back only if the toolchain tolerates it
    • add an extension-specific watcher exclude once available
    • raise fs.inotify.max_user_watches only as a short-term escape hatch, because it can hide the recursion bug and make the next failure larger

    Disclosure: I maintain a small storage-cleanup checklist site. I wrote up a Linux inotify-specific runbook here because this class is easy to confuse with real disk-full cleanup: https://www.getsafedisks.com/ai-agent-inotify-watch-enospc-linux?product=pilot_audit&utm_source=github&utm_medium=issue-comment&utm_campaign=agent-storage-issue&utm_term=codex-vscode-inotify-watch-enospc-large-workspace&utm_content=openai-codex-23574

  5. tomasruizt commented on Jun 24, 2026

    @tomasruizt

    This also affects me. I'm disabling and deleting the Codex extension for now.

  6. Pascu-Victor commented on Jun 29, 2026

    @Pascu-Victor

    I hit this with the VS Code Codex extension on Linux. The failure appears related to the extension using:

      fs.watch(path, { recursive: true }, listener)

    On Linux, that recursive watch path can fail or exhaust inotify watcher limits on larger workspaces. A proper patch would be to use the VS Code file watch API.

    A temporary local workaround is to intercept only recursive Linux fs.watch calls before loading the real extension bundle, and route them through VS Code’s watcher API instead:
    Create ~/.vscode/extensions/openai.chatgpt-26.623.70822-linux-x64/wrapper.js

    "use strict";
    
    const fs = require("node:fs");
    const path = require("node:path");
    const { EventEmitter } = require("node:events");
    
    const originalWatch = fs.watch.bind(fs);
    
    function shouldUseVsCodeWatcher(options) {
      return process.platform === "linux" && options?.recursive === true;
    }
    
    function createVsCodeRecursiveWatcher(root, listener) {
      const watcher = new EventEmitter();
      const vscode = require("vscode");
      const pattern = new vscode.RelativePattern(vscode.Uri.file(root), "**/*");
      const fileWatcher = vscode.workspace.createFileSystemWatcher(pattern);
    
      const emitChange = (eventType, uri) => {
        const relativePath = path.relative(root, uri.fsPath);
        listener?.(eventType, relativePath || path.basename(uri.fsPath));
      };
    
      fileWatcher.onDidCreate((uri) => emitChange("rename", uri));
      fileWatcher.onDidDelete((uri) => emitChange("rename", uri));
      fileWatcher.onDidChange((uri) => emitChange("change", uri));
    
      watcher.close = () => {
        fileWatcher.dispose();
      };
    
      return watcher;
    }
    
    fs.watch = function patchedWatch(filename, options, listener) {
      if (typeof options === "function") {
        listener = options;
        options = undefined;
      }
    
      if (shouldUseVsCodeWatcher(options)) {
        try {
          return createVsCodeRecursiveWatcher(path.resolve(String(filename)), listener);
        } catch {
          return originalWatch(filename, { ...options, recursive: false }, listener);
        }
      }
    
      return originalWatch(filename, options, listener);
    };
    
    module.exports = require("./extension.js");

    in package.json for the extension replace

      "main": "./out/extension.js",

    with the wrapper

      "main": "./out/wrapper.js",

    Quick one liner to check if the problem has gone away, run in root shell

    find /proc/*/fd/ -type l -lname "anon_inode:inotify" -printf "%hinfo/%f\n" | xargs grep -cE "^inotify" | sort -nk2 -t: | sed -E 's/:([0-9]+)$/\t\t\1/' | tail -10

    before

    /proc/1048513/fdinfo/44   46
    /proc/2613/fdinfo/18      49
    /proc/3148/fdinfo/14      62
    /proc/1974/fdinfo/537     112
    /proc/2267/fdinfo/7       134
    /proc/1/fdinfo/7          150
    /proc/1974/fdinfo/532     191
    /proc/1048513/fdinfo/47   38085 <- vscode file watch process
    /proc/1048455/fdinfo/104  458280 <- vscode extension host eating 450K inotify watches!
    

    after

    /proc/3977877/fdinfo/31         30
    /proc/3990348/fdinfo/30         31
    /proc/517243/fdinfo/31          31
    /proc/2734/fdinfo/15            49
    /proc/3173/fdinfo/14            62
    /proc/1992/fdinfo/521           117
    /proc/2462/fdinfo/7             135
    /proc/1/fdinfo/7                152
    /proc/1992/fdinfo/528           206
    /proc/3990300/fdinfo/47         40681  <- vscode  file watch process
    
  7. russpatterson commented on Jul 1, 2026

    @russpatterson

    I’m seeing what appears to be the same issue on a newer VS Code Codex extension build.

    Environment:

    • VS Code Remote WSL
    • Codex extension: openai.chatgpt-26.623.70822-linux-x64
    • Workspace is under WSL Linux home: /home/.../image_generator
    • Workspace is not under /mnt/c
    • The repo had high-churn generated image-rendering output under image_jobs/

    The generated output included render job files, plan JSON files, and rendered PNG frames. These directories were already excluded from the normal project/file-watcher paths:

    • image_jobs/ was in .gitignore
    • .vscode/settings.json had files.watcherExclude for **/image_jobs/**
    • .vscode/settings.json had search.exclude for **/image_jobs/**

    Observed behavior:

    • The machine became sluggish while image rendering jobs were running.
    • The render/scheduler processes were not the CPU hog:
      • gpu_scheduler.py: about 1.4-1.5% CPU
      • run_web.py: about 1.0-1.1% CPU
    • The hot process was the VS Code remote extensionHost:
      • sustained around 82-83% CPU
      • CPU was concentrated on the extension host main Node thread
    • The Codex app-server child was only around 1% CPU.

    The VS Code remote extensionHost process held about 463,303 inotify watches, while the WSL inotify watch limit was 524,288. So the extension host was close to exhausting the Linux file-watch limit.

    The Codex extension logs repeatedly showed:

    [git-repo-watcher] Git repo watcher failed errorCode=ENOSPC
    ENOSPC: System limit for number of file watchers reached
    The failed watch paths included generated image output and git internals, for example:
    /home/.../image_generator/image_jobs/.../rendered_frames/R_...png
    /home/.../image_generator/image_jobs/.../plans/P_...json
    /home/.../image_generator/.git/objects/...
    Stopping the GPU scheduler improved the symptom only because it stopped creating new files under image_jobs/. The CPU load itself appeared to come from the Codex extension-side watcher reacting to those generated files, not from the render process.
    To make the machine usable again, I had to move the image rendering job, plan, and rendered-output directories out of the real repo tree so Codex would stop recursively watching them. That reduced the responsiveness problem, but it is only a workaround.
    This seems to confirm that the Codex extension-side watcher is bypassing VS Code’s normal watcher excludes and/or .gitignore, recursively watching high-churn generated output and .git/objects, then driving extensionHost CPU and inotify pressure.
    
  8. interconnectedMe commented on Jul 1, 2026

    @interconnectedMe
    Author

    Today: 357,817 inotify watches.

    What version of the IDE extension are you using?

    openai.chatgpt-26.513.21555-linux-x64

    What subscription do you have?

    ChatGPT Pro

    Which IDE are you using?

    VS Code 1.120.0

    What platform is your computer?

    Linux 6.17.0-29-generic x86_64 x86_64

    What issue are you seeing?

    On Linux, the VS Code Codex extension can drive the user session close to or beyond the inotify watch limit in a large workspace. The high watch count is owned by the VS Code extension host process, not by VS Code's normal file watcher and not by the Codex app-server child.

    Observed measurements:

    openai.chatgpt disabled in the VS Code Planning profile: about 80k-90k total watches
    openai.chatgpt enabled and Codex chats opened/resumed: about 1,048k to 1,234k total watches
    VS Code extension host process during bad state: about 900k-1,151k watches
    normal VS Code file-watcher process during bad state: about 3k-79k watches
    Codex app-server child during bad state: about 213 watches
    

    The impact was desktop-wide inotify exhaustion: logs showed ENOSPC, No space left on device, and OS file watch limit reached, with collateral failures in the Linux desktop session.

    Relevant Codex log excerpts from the bad state:

    Features enabled ... workspace_dependencies ...
    [git-repo-watcher] Starting git repo watcher
    codex_file_watcher: failed to watch /etc: OS file watch limit reached
    codex_file_watcher: failed to watch /media/S_Drive/projects/strategy-tester/.agents/skills: OS file watch limit reached
    codex_app_server_transport::transport: dropping overload response ... outbound queue is full
    [git-repo-watcher] Git repo watcher failed ... ENOSPC ... watch '/media/S_Drive/projects/strategy-tester/.git/objects/...'
    

    This workspace has large generated/runtime trees, but they are excluded from VS Code's normal watcher:

    "files.watcherExclude": {
    "/.sandcastle/worktrees/": true,
    "/data/": true,
    "/logs/": true
    }
    The normal VS Code file watcher stayed low, which suggests the Codex extension-side watcher path is bypassing VS Code's files.watcherExclude and/or recursively watching too much Git/workspace state.

    What steps can reproduce the bug?

    1. On Linux, open a large VS Code workspace with the Codex extension enabled.
    2. Use a workspace with large generated/runtime directories under the repo root. In my case, before local mitigation:
    repo total:              about 1,071,929 files
    logs/:                   about   716,933 files
    data/:                   about   129,956 files
    .sandcastle/worktrees/:  about   102,877 files
    
    1. Configure VS Code workspace excludes for those large directories, for example:

    "files.watcherExclude": {
    "/.sandcastle/worktrees/": true,
    "/data/": true,
    "/logs/": true
    }
    4. Start or resume Codex chats in the VS Code Codex panel. A focused repro opened one existing Codex chat, then opened about 3-4 additional Codex chats.
    5. Monitor inotify watches:

    sudo bash -c 'total=0; for f in /proc/[0-9]/fdinfo/; do n=$(grep -c "inotify wd:" "$f" 2>/dev/null || true); total=$((total+n)); done; echo "$total"'

    for pid in $(find /proc//fd -lname anon_inode:inotify 2>/dev/null | sed 's#/proc/##; s#/fd/.##' | sort -u); do
    watches=$(grep -h "inotify wd:" /proc/$pid/fdinfo/* 2>/dev/null | wc -l)
    comm=$(cat /proc/$pid/comm 2>/dev/null)
    cmdline=$(tr "\0" " " < /proc/$pid/cmdline 2>/dev/null | cut -c1-220)
    printf '%8s %7s %-18s %s\n' "$watches" "$pid" "$comm" "$cmdline"
    done | sort -nr | head -20
    Observed focused repro:

    10:08:58 total_watches=83,205
    10:10:08 total_watches=83,205
    10:11:18 total_watches=1,234,730
    10:12:37 total_watches=1,234,736
    10:13:55 total_watches=1,234,736
    11:02:12 total_watches=1,234,754
    

    The watches did not release after closing the extra Codex chat tabs/panels, and they remained after about 30 minutes. Developer: Reload Window briefly dropped the count, but the extension restarted and re-triggered the high watcher state.

    Disabling workspace_dependencies through the bundled Codex CLI did not prevent this extension-side watcher path. The CLI reported the feature as disabled, but after VS Code reload the extension log still listed workspace_dependencies, started [git-repo-watcher], and the extension host climbed back to about 1.23M total watches.

    What is the expected behavior?

    The Codex VS Code extension should not recursively allocate hundreds of thousands or more than one million inotify watches in the extension host for a workspace where VS Code's own file watcher is correctly constrained by files.watcherExclude.

    Expected behavior:

    • Respect VS Code workspace watcher excludes or apply equivalent filtering before recursive extension-side watching.
    • Avoid recursively watching .git/objects and large generated/runtime directories.
    • Bound watcher allocation and degrade gracefully if a workspace is too large.
    • Release extension-created watches when Codex chat tabs/panels are closed or when the triggering state ends.
    • Avoid desktop-wide ENOSPC/inotify exhaustion.

    Additional information

    The strongest isolation signal is process ownership:

    normal VS Code file watcher: low watch count
    Codex app-server child: about 213 watches
    VS Code extension host: about 1,151,500 watches
    

    A local mitigation confirmed that real workspace tree size drives the spike. Moving logs/ outside the real workspace tree and symlinking it back removed about 731k watches:

    Before: Codex extension host about 1,151,522 watches
    After moving logs/ out of the real tree: Codex extension host about 420,306 watches
    

    That mitigation is only a workaround. It also shows that the extension host appears to expand the real filesystem tree under the workspace root instead of honoring the configured VS Code watcher excludes.

    Closest related issue I found: #23191 reports the same general git-repo-watcher/ENOSPC family in Cursor Remote SSH when $HOME accidentally becomes a large Git repo. This issue is separate because it reproduces in VS Code with an intended repo workspace, measured extension-host watch ownership, and normal VS Code watcher excludes already in place.

    Adjacent but not identical: #22421, #17394, #20295.

  9. kyle3728 commented on Jul 6, 2026

    @kyle3728

    Adding another data point from a WSL / VS Code Server workspace that matches this issue closely.

    Environment:

    • Extension: openai.chatgpt-26.5623.101652-linux-x64
    • Host: VS Code Server in WSL
    • Workspace root: a large repo at /home/kyle/projects/finance_toolkit
    • Existing workspace settings already exclude **/.worktrees/**, **/.git/objects/**, **/node_modules/**, **/.cache/**, **/.tmp/**, **/.harness/**, etc. via files.watcherExclude and search.exclude.
    • Kernel limits at the time were already relatively high: fs.inotify.max_user_watches=1048576, fs.inotify.max_user_instances=8192.

    Relevant extension log lines show the extension-private watcher path, not just VS Code core file watching:

    2026-07-03 01:07:02.193 [info] [git-repo-watcher] Starting git repo watcher
    2026-07-03 10:15:50.217 [warning] [git-repo-watcher] Git repo watcher failed errorCode=ENOSPC errorMessage="ENOSPC: System limit for number of file watchers reached, watch `/home/kyle/projects/finance_toolkit/.worktrees/harness-golden-usage-closeout/.tmp-harness-golden-symlink-target`" path=/home/kyle/projects/finance_toolkit
    2026-07-03 10:18:10.270 [warning] [git-repo-watcher] Git repo watcher failed errorCode=ENOSPC errorMessage="ENOSPC: System limit for number of file watchers reached, watch `/home/kyle/projects/finance_toolkit/.worktrees/harness-golden-usage-closeout/.cache/test-harness/docker-config/buildx`" path=/home/kyle/projects/finance_toolkit
    2026-07-03 10:26:02.993 [warning] [git-repo-watcher] Git repo watcher failed errorCode=ENOSPC errorMessage="ENOSPC: System limit for number of file watchers reached, watch `/home/kyle/projects/finance_toolkit/.git/worktrees/harness-golden-usage-closeout/index.lock`" path=/home/kyle/projects/finance_toolkit
    2026-07-03 10:31:24.006 [warning] [git-repo-watcher] Git repo watcher failed errorCode=ENOSPC errorMessage="ENOSPC: System limit for number of file watchers reached, watch `/home/kyle/projects/finance_toolkit/.worktrees/harness-golden-usage-closeout/.harness/review`" path=/home/kyle/projects/finance_toolkit
    

    The key behavior is that the Codex extension git repo watcher appears to recurse into paths that users would reasonably expect to be ignored for watcher purposes: .worktrees, .git/worktrees, .harness, nested cache directories, and generated test harness output. In this workspace, .worktrees contains agent-created git worktrees with their own dependencies and harness artifacts, so this can exhaust the watch budget even when VS Code core excludes are configured.

    The most practical workaround we have identified is to move future git worktrees outside the opened VS Code workspace root, for example from:

    /home/kyle/projects/finance_toolkit/.worktrees/<name>
    

    to a sibling root such as:

    /home/kyle/projects/finance_toolkit-worktrees/<name>
    

    Raising the inotify limits helps temporarily, but it does not address the underlying issue that extension-private watching does not appear to honor the normal workspace exclude configuration. An extension-level watcher exclude setting, or default ignores for .git, .worktrees, node_modules, .cache, .tmp, and .harness, would likely fix this class of workspace.

  10. rfunderburk commented on Jul 7, 2026

    @rfunderburk

    I have the same issue. I asked codex to patch itself and it found:

    The extension directly calls fs.watch() with recursive watching enabled, bypassing VS Code watcher exclusions. Changing the bundled expression from:
    Kr.default.watch(i,{recursive:e.recursive}
    to:
    Kr.default.watch(i,{recursive:false}
    stops the excessive watcher growth after reloading VS Code. Extension updates restore the original behavior.

  11. zuuxuux commented on Jul 8, 2026

    @zuuxuux
    I’m seeing what looks like the same bug family in Codex Desktop on Linux.
    
    Environment:
    - Codex Desktop process: `/opt/codex-desktop/electron`
    - OS: Linux desktop
    - Repo type: Vite/React app with `frontend/node_modules` present
    - Kernel limits:
      - `fs.inotify.max_user_watches = 65536`
      - `fs.inotify.max_user_instances = 128`
    
    Observed failure:
    - Running the repo’s normal startup eventually failed in Vite with:
    
    ```text
    Error: ENOSPC: System limit for number of file watchers reached, watch '/home/<user>/code/<repo>/frontend/vite.config.ts'

    But read-only debugging showed Vite was not the process consuming the watches.

    Watcher ownership:

    visible_inotify_watches=65582
    visible_inotify_instances=96
    
    64676 watches  PID <pid>  /opt/codex-desktop/electron ...
    271 watches    PID <pid>  .../codex app-server ...
    0 watches      PID <pid>  node /home/<user>/code/<other-worktree>/frontend/node_modules/.bin/vite ...
    

    Sample watched paths owned by the Codex Desktop Electron process resolved to ignored/generated directories inside another worktree:

    /home/<user>/code/<other-worktree>/frontend/node_modules/@firebase/auth/dist/esm2017/src/index.d.ts
    /home/<user>/code/<other-worktree>/frontend/node_modules/@firebase/auth/dist/esm2017/src/core/util/browser.d.ts
    /home/<user>/code/<other-worktree>/frontend/node_modules/@firebase/auth/dist/esm2017/src/mfa/index.d.ts
    /home/<user>/code/<other-worktree>/.git/refs/heads/...
    /home/<user>/code/<other-worktree>/.agents/skills/...
    

    The Codex Desktop log also directly shows the git repo watcher trying to watch node_modules:

    [git-repo-watcher] Git repo watcher failed errorCode=ENOSPC
    errorMessage="ENOSPC: System limit for number of file watchers reached, watch '/home/<user>/code/<other-worktree>/frontend/node_modules/@firebase/auth/dist/node-esm/index.js'"
    path=/home/<user>/code/<other-worktree>
    

    The repo already ignores these directories:

    frontend/node_modules/
    frontend/dist/
    frontend/storybook-static/
    

    And Vite itself appears to ignore **/.git/** and **/node_modules/** by default, so the Vite error was collateral damage: Codex Desktop had already consumed nearly the whole per-user inotify budget.

    This reproduced after a fresh system restart, so it does not appear to be stale pre-reboot processes. It appears to be recreated by Codex Desktop’s watcher after opening/resuming sessions.

    Local conclusion:

    • Codex Desktop’s git-repo-watcher appears to recursively watch ignored/generated dependency trees such as frontend/node_modules.
    • On Linux default inotify limits, one worktree with ~77k node_modules files is enough to exhaust the user watch budget.
    • The downstream symptom can appear in unrelated tools, e.g. Vite failing to watch vite.config.ts.

    Suggested fix direction:

    • Exclude node_modules, dist, storybook-static, .venv, cache/build artifact directories, and probably most .git internals from Codex Desktop recursive watchers.
    • Respect .gitignore or equivalent workspace excludes before allocating recursive watches.
    • Add bounds/backoff/degraded polling behavior when watcher allocation approaches or hits ENOSPC.
    • Surface a clear warning naming the owning Codex watcher and path, rather than allowing unrelated tools to fail later.
  12. jinyuliao commented on Jul 13, 2026

    @jinyuliao

    Independent reproduction on VS Code Remote SSH with Codex IDE extension 26.707.41301.

    Sanitized observations:

    • The workspace contained approximately 788k files and 70k directories; a generated build subtree accounted for approximately 385k files and 34k directories.
    • VS Code files.watcherExclude rules were already configured for generated and log trees, but they did not constrain the Codex git-repo-watcher behavior.
    • Under inotify pressure, the Codex panel stopped appearing reliably.
    • Temporarily raising fs.inotify.max_user_watches from 524288 to 2097152 did not reliably restore the panel, so increasing the kernel limit is not a durable fix.
    • Reload cycles produced multiple extension-host/workspace-lock activity, which may compound watcher allocation.
    • Disabling Codex only for this large workspace removed the immediate trigger; the system watch limit was then restored to 524288.

    This appears consistent with the extension-side watcher bypassing VS Code watcher exclusions. Please consider:

    1. Applying files.watcherExclude or equivalent filtering to git-repo-watcher.
    2. Avoiding recursive watches of generated trees and Git object storage.
    3. Bounding watcher allocation and degrading gracefully.
    4. Deduplicating and releasing watches across extension-host reloads.

    No code, repository contents, file paths, host addresses, usernames, attachments, or raw logs are included in this report.

  13. LewisLyx commented on Jul 17, 2026

    @LewisLyx

    Additional Dev Container reproduction:

    • Extension: openai.chatgpt-26.5707.91948-linux-x64
    • VS Code Server commit: 125df4672b8a6a34975303c6b0baa124e560a4f7
    • Workspace output tree: 28 GB
    • .git directory: 6.5 GB
    • fs.inotify.max_user_watches: 1048576

    Codex.log reports:
    [git-repo-watcher] ENOSPC: System limit for number of file watchers reached

    The remote extension host then reaches about 2041 MB V8 heap and crashes:
    FATAL ERROR: JavaScript heap out of memory
    Extension Host Process exited with signal SIGABRT

    Docker/cgroup OOM is ruled out:
    OOMKilled=false
    memory.events: oom=0, oom_kill=0

    files.watcherExclude does not appear to constrain the Codex watcher.

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

    bugSomething isn't workingextensionIssues related to the VS Code extensionperformance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions