Skip to content

VS Code extension sandbox leaves empty .git directory, causing Git discovery CPU spin #28631

Open

Description

@hkwi

Summary

When using the Codex VS Code extension in a non-Git workspace on a Linux remote environment, Codex sandbox setup appears to leave an empty .git directory on the host workspace root. VS Code Git then repeatedly treats the folder as a Git repository candidate and spawns git rev-parse --show-toplevel, causing the VS Code extension host to consume high CPU continuously.

Environment

  • VS Code Server: 1.124.2
  • Codex VS Code extension: openai.chatgpt 26.609.30741 linux-x64
  • Platform: Linux remote environment, likely WSL2
  • Codex sandbox: workspace-write / bubblewrap
  • Observed affected workspaces:
    • $HOME/avatra
    • $HOME/tmp/cf

Observed Behavior

  1. The workspace is not a Git repository and initially has no valid .git directory.

  2. After using Codex in the workspace, an empty host-visible .git directory appears at the workspace root.

  3. The directory has no .git/HEAD.

  4. VS Code Git repeatedly runs:

    git -c core.hooksPath=/dev/null -c core.fsmonitor= rev-parse --show-toplevel
    
  5. Git fails with:

    fatal: not a git repository (or any of the parent directories): .git
    
  6. The VS Code extension host stays at roughly 50-65% CPU.

Evidence

For one affected extension host PID, a 10 second strace sample showed:

  • 70,503 syscalls
  • 4,256 execve calls
  • 304 clone calls
  • 611 wait4 calls
  • 211 /usr/bin/git executions in $HOME/tmp/cf

The repeated command was:

git -c core.hooksPath=/dev/null -c core.fsmonitor= rev-parse --show-toplevel

The trace showed:

  • $HOME/tmp/cf/.git exists
  • $HOME/tmp/cf/.git/HEAD returns ENOENT

The same pattern was previously observed in another workspace, with 324 git rev-parse executions in 10 seconds.

A Codex sandbox command line also included a mount entry like:

--tmpfs $HOME/tmp/cf/.git --remount-ro

That suggests the sandbox may be creating a host-side mountpoint for .git, then leaving the empty directory behind after sandbox use.

Expected Behavior

Codex sandbox setup should not leave an empty .git directory on the host filesystem for a non-Git workspace. If a private .git mount is needed inside the sandbox, it should not persist as a host-visible directory after the sandbox exits.

Actual Behavior

An empty host-visible .git directory remains. VS Code Git sees it and repeatedly retries Git discovery, causing high CPU in the extension host.

Related Log Noise

The Codex log also repeatedly contains:

Received broadcast but no handler is configured method=thread-stream-state-changed

This may be separate, but strace shows the dominant CPU source is the Git discovery loop caused by the empty .git directory.

Feedback UI Issue

I also attempted to submit this via /feedback. The UI showed no confirmation and no session ID, although the Codex manual says a session ID should be shown after submission.

The local Codex log contains:

codex_app_server::request_processors::feedback_doctor_report: timed out running doctor report for feedback; skipping attachment

So I cannot tell whether the in-product feedback submission actually succeeded.

Workarounds

  • Remove the empty .git directory with rmdir <workspace>/.git

  • Disable Git integration for the affected workspace:

    {
      "git.enabled": false
    }
  • Reload or restart the VS Code extension host

Activity

  1. added
    bugSomething isn't working
    extensionIssues related to the VS Code extension
    sandboxIssues related to permissions or sandboxing
    on Jun 17, 2026
  2. hkwi commented on Jun 17, 2026

    @hkwi
    Author

    Related issues I found after filing:

    So this may be a cross-product of #26463 and #17394: sandbox leaves or exposes a .git path that makes the IDE Git metadata/discovery loop pathological.

  3. nken-eccs commented on Jul 16, 2026

    @nken-eccs

    I can confirm this issue is still present in openai.chatgpt-26.707.91948-linux-x64.

    In my case, $HOME was not a Git repository, but $HOME/.git existed as a completely empty directory. While Codex was active, the Extension Host repeatedly ran:

    git -c core.hooksPath=/dev/null -c core.fsmonitor= rev-parse --show-toplevel
    

    I observed approximately 750–1,287 executions every 5 seconds.

    • Extension Host CPU: 59–66%, mostly system CPU
    • Minor faults: 30,000–46,000/s
    • Voluntary context switches: 570–814/s
    • codex app-server CPU: only about 2–4%

    Confirmed loop

    GitInitWatcher.start()
      -> checkForGitDirectory("$HOME/.git")
      -> stat(".git") succeeds
      -> watcher is disposed and onGitInit() is called
      -> handleGitInit()
      -> invalidateStableMetadata()
      -> getStableMetadata()
      -> git rev-parse --show-toplevel
      -> exit 128 / null metadata
      -> ensureWatchingForGitInit()
      -> new GitInitWatcher.start()
      -> stat(".git") succeeds again
    

    Because the empty .git directory continues to exist, the newly created watcher immediately follows the same path. There is no delay or backoff between attempts.

    Renaming the empty directory stopped the loop without reloading VS Code or restarting the Extension Host:

    mv "$HOME/.git" "$HOME/.git.empty"

    In the next measurement window:

    • repeated rev-parse executions dropped to 0
    • Extension Host CPU dropped to 0.2–0.4%
    • minor faults dropped to 23–88/s
    • voluntary context switches dropped to 13–17/s

    Suggested fixes

    1. checkForGitDirectory() should not treat a successful stat(".git") as completed Git initialization. It should verify that the path resolves to valid Git metadata before disposing the watcher and calling onGitInit().

    2. When handleGitInit() receives null metadata, it should not call ensureWatchingForGitInit() immediately. The retry should use a bounded exponential backoff, for example:

      1s -> 2s -> 5s -> 10s -> 30s maximum
      
    3. A negative Git-root result should be cached per host and cwd for the backoff period, so repeated metadata invalidation cannot immediately spawn another git process.

    4. If the sandbox creates .git as a host-side mountpoint, it should remove that directory when the sandbox exits if it did not exist before and is still empty.

    5. Add a regression test that creates an empty .git directory in a non-Git cwd and verifies that Git discovery attempts remain bounded.

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 extensionperformancesandboxIssues related to permissions or sandboxing

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions