Codex desktop exhausts the Linux file-watch limit by watching .venv, cache, and Git-internal files

Open 💬 2 comments Opened Aug 19, 2026 by Ermir76

What version of the Codex App are you using (From “About Codex” dialog)?

26.814.41957

What subscription do you have?

ChatGPT Pro

What platform is your computer?

Ubuntu 26.04 LTS (Resolute Raccoon), Linux kernel 7.0.0-30-generic, x86_64

What issue are you seeing?

When I use Codex desktop with several local repositories, the ChatGPT process consumes nearly the entire Linux inotify file-watch allowance.
On my computer, ChatGPT owned 65,082 watches while the system limit was 65,536. This prevents other applications from creating file watches and can stop them from opening or monitoring projects correctly.
Codex’s git-repo-watcher is watching large numbers of files that should normally be excluded, including:

  • Repository .venv dependencies
  • __pycache__ directories
  • .git/objects
  • .git/refs/codex/turn-diffs
  • Files inside Git submodules
  • Generated and cached files

The logs repeatedly report:
ENOSPC: System limit for number of file watchers reached

I also recorded 118 “Starting git repo watcher” events within approximately 20 minutes.
I have not proven that completed tasks leave stale watches behind. The confirmed problem is that each watcher covers far too many unnecessary files.

What steps can reproduce the bug?

Use Codex desktop on Linux with several local repositories.
Have ordinary Python virtual environments inside the repositories, such as .venv.
Open several Codex tasks across different repositories.
Run longer tasks, including tasks that use agents or sub-agents.
Leave Codex open and move between these tasks for approximately 20 minutes.
Check the Linux watch limit:
sysctl fs.inotify.max_user_watches

Count the watches owned by the main ChatGPT process:
pid=$(pgrep -o -f '/usr/lib/chatgpt/ChatGPT')
grep -h '^inotify' /proc/$pid/fdinfo/* | wc -l

Inspect the logs:
journalctl --user -o cat | grep -E 'git-repo-watcher|ENOSPC|file watchers'

Observe that ChatGPT approaches the system limit and reports failures for paths inside .venv, caches, and Git-internal directories.

What is the expected behavior?

Codex should watch only the files needed to detect meaningful project changes.
It should ignore .venv, __pycache__, dependencies, caches, generated files, and most internal Git files.
Codex should reuse watchers when several tasks use the same repository. It should also release watchers when they are no longer needed.
Using several projects at the same time should not prevent other applications from working.

Additional information

I found several related reports, but none is an exact open report for my current Codex desktop problem.
Issue #33234 described almost the same Codex desktop behavior. Its author closed it one minute after creating it because they believed it was in the wrong repository. It was not closed because the bug was fixed.
Issue #23574 remains open and reports the same general watcher problem in the VS Code Codex extension. My report concerns the standalone ChatGPT desktop application while using Codex.
Issue #39123 is a recent Fedora report, but it concerns many helper processes holding empty watcher objects. My case concerns the main ChatGPT process watching approximately 65,000 actual files and folders.
My measurements were:

  • Linux limit: 65,536 file watches
  • Main ChatGPT process: 65,082 file watches
  • First watcher group: 51,797 watched files
  • Second watcher group: 13,279 watched folders
  • Logs: 118 “Starting git repo watcher” messages in approximately 20 minutes

Watched paths included .venv, __pycache__, .git/objects, .git/modules, and .git/refs/codex/turn-diffs.
I collected and checked these measurements directly on my computer.

View original on GitHub ↗

2 Comments

meirLixen · 2 days ago

Confirming this on a different stack, and adding root-cause evidence from the shipped bundle plus a node_modules case that makes the scale worse than .venv.

Environment: ChatGPT desktop 26.818.41705, Ubuntu 22.04.5 LTS, kernel 6.8.0-138-generic.

Root cause in the shipped code. In /usr/lib/chatgpt/resources/app.asar, the git-repo-watcher class (logger name git-repo-watcher, telemetry op codex.git.watcher_metadata) registers its working-tree watch target with recursive: true. That watch target carries no ignore list at all — there is no node_modules/.venv exclusion, no .gitignore awareness, and no setting that scopes or disables it. On Linux the backend is inotify, so a recursive watch costs one watch per directory in the tree. For contrast, the neighbouring git-init-watcher in the same bundle correctly uses recursive: false.

Scale on a JS monorepo. My workspace is a multi-repo Node.js tree:

dirs total:            103,725
inside node_modules:    90,600   (87%)
fs.inotify.max_user_watches: 65,536

So a single connected folder asks for ~1.6x the entire per-user allowance, and 87% of that is dependency directories that can never produce a meaningful git change. Failures in one day:

$ journalctl --since today | grep -c inotify_add_watch
6,493      # all from chatgpt.desktop, none from any other process

Sample paths it tried to watch:

job-watcher/node_modules/@opentelemetry/otlp-transformer/build/esm/metrics/protobuf
login-service/node_modules/@elastic/transport/node_modules/@opentelemetry/api/build/esm/baggage/internal
node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot/dist

Why this deserves priority over a normal watcher bug. max_user_watches is a per-user, system-wide resource. Once the desktop app drains it, every other process on the machine silently loses file watching — editors, dev servers, bundlers, test runners. The app degrades tools it has nothing to do with, and the failure surfaces in those tools, so users do not attribute it to Codex.

Suggested fix, cheapest first: the working-tree watcher only needs to know that the tree changed, so honouring .gitignore (or even a hardcoded skip of node_modules, .venv, __pycache__, .git/objects) at the recursive-watch level would remove the overwhelming majority of watches. A user-facing opt-out would be a reasonable stopgap while that lands.

Neither documented workaround is acceptable as a default: not connecting large repos defeats the product, and raising max_user_watches asks every Linux user to re-tune a kernel limit because one app has no exclusion list.

raul-cgk · 2 days ago

Confirming this on another supported Ubuntu system, including direct /proc mapping and an independent check of the latest shipped bundle.

Environment

  • Ubuntu 24.04.4 LTS, kernel 6.8.0-138-generic, x86_64
  • ChatGPT desktop 26.820.60940
  • Installed package matched the current APT candidate when measured
  • Multiple complete application restarts have provided only temporary relief; the same exhaustion returns

Direct inotify evidence

At one verified high-water snapshot:

  • fs.inotify.max_user_watches = 65,536
  • Total watches owned by the user: 65,496
  • Main ChatGPT process: 62,202 watches across four inotify instances
  • All other processes combined: 3,294 watches

The same main PID released and recreated large watch groups during sampling; observed counts included 29,824 -> 4,909 -> 26,675 -> 4,909 -> 15,437 -> 62,202. This is not merely one stable legitimate watch set.

I mapped the two dominant instances through their /proc/<pid>/fdinfo inode/device records:

  • About 15,432 watches mapped entirely to Git metadata trees.
  • A 46,762-watch working-tree instance mapped completely to repository paths:
  • 29,171 under .venv
  • 13,854 under generated dependency trees
  • 955 under generated build output
  • 1,485 under nested worktrees outside the categories above
  • 556 under node_modules
  • 741 other paths

Repository names, usernames, and absolute paths are intentionally omitted.

Independent latest-build implementation check

In the current /usr/lib/chatgpt/resources/app.asar, I independently confirmed that git-repo-watcher adds the repository root as a working-tree directory target with recursive: true. The file-watch request contains no registration-time ignore list. Failed watch sessions are scheduled for retry after 1,000 ms. The Git-internal-path predicate is used when handling delivered events, not to prevent recursive watches from being allocated.

A separate 30-second observation found main-process RSS cycling between roughly 646 MiB and 1.39 GiB while the PID remained unchanged. I am not claiming that short sample alone proves a monotonic memory leak, but it is consistent with the repeated watcher construction and teardown.

This evidence supports an application defect triggered by large but ordinary project layouts, rather than an inotify or disk configuration problem. The key fixes appear to be registration-time exclusions, repository-level watcher deduplication, and bounded/backed-off recovery after quota exhaustion.