Codex IDE sidebar Git-origin polling triggers severe Windows PID 4 Section-handle growth

Open 💬 3 comments Opened Jul 28, 2026 by tmesias
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Bug: Codex IDE sidebar Git-origin polling triggers severe Windows PID 4 Section-handle growth

Summary

On one Windows workstation, enabling the OpenAI Codex VS Code extension causes
a continuous storm of short-lived git.exe and conhost.exe processes. This
correlates with severe accumulation of unnamed Section handles in Windows PID
4 (System), eventually causing system-wide resource exhaustion.

A controlled uninstall/reinstall test reproduced the problem on two Codex
extension builds. Removing Codex stops both the Git process storm and sustained
PID 4 handle growth. Freshly reinstalling Codex makes both return.

Environment

  • Operating system: Windows 11 x64
  • VS Code: 1.130.0
  • Git for Windows installed
  • Original affected Codex extension: openai.chatgpt@26.721.30844
  • Freshly reinstalled Codex extension: openai.chatgpt@26.721.41059
  • Repositories include a relatively large set of historical local/network

workspaces associated with prior Codex threads.

Reproduction and controlled results

Codex installed and active

Before uninstall:

  • Repeated Git operations appeared every few seconds.
  • Representative commands:
  • git -c core.hooksPath=NUL -c core.fsmonitor= for-each-ref --count=100 ...
  • git config --null --get core.fsmonitor
  • git -c core.hooksPath=NUL -c core.fsmonitor= rev-parse --abbrev-ref HEAD
  • git -c core.hooksPath=NUL -c core.fsmonitor= remote
  • Codex logs identified the repeating request as:
  • requestKind=git-origins
  • source=sidebar_workspace_task_groups_task_dirs
  • PID 4 handle growth repeatedly measured approximately 15–22 handles/second.
  • One 20-second sample measured +357 handles (17.85 handles/second).
  • A three-minute sample observed 474 new Git processes and 360 new conhost

processes.

Disabling VS Code's built-in Git integration did not stop the behavior.
Removing GitLens and a third-party Claude/Codex history extension also did not
stop it.

Codex uninstalled

After removing openai.chatgpt and confirming that no codex.exe process was
running:

  • Three consecutive one-minute PID 4 rates were:
  • -0.16 handles/second
  • -0.54 handles/second
  • +2.68 handles/second
  • Zero Git processes were observed.
  • An extended 15-minute test averaged 1.02 PID 4 handles/second.
  • Zero Git processes were observed throughout that 15-minute window.

Fresh Codex reinstall

After installing openai.chatgpt@26.721.41059:

  • PID 4 increased by 1,472 handles in 60 seconds: 24.53 handles/second.
  • 172 short-lived Git processes were observed in the same minute.
  • The Git commands reproduced the same core.hooksPath=NUL,

core.fsmonitor=, for-each-ref, rev-parse, and remote pattern.

  • The dominant direct parents were active VS Code extension-host processes.
  • PID 4 had accumulated more than 624,000 handles when checked.

Kernel/object analysis

Read-only Sysinternals Handle inventories and LiveKD analysis established that
the PID 4 growth is almost entirely unnamed Section handles. Representative
objects had:

  • object type: Section
  • no name
  • access mask: 0x000f001f
  • one PID 4 handle
  • pointer count: 32767
  • one mapped view
  • one 4 KB committed pagefile-backed page

The evidence supports the Codex Git-process storm as the repeatable trigger. It
does not establish that Codex itself owns or directly leaks the kernel objects;
the Windows process-creation/teardown path may retain them after the rapid
short-lived process launches.

Expected behavior

The sidebar should not continuously rescan the Git origins of a large
historical task-directory set. Background repository discovery should be
bounded, cached, cancellable when the view is inactive, and should not create
hundreds of processes per minute.

Actual behavior

The Codex sidebar repeatedly scans historical task directories, creating
hundreds of short-lived Git/conhost processes and driving sustained PID 4
Section-handle growth until the workstation approaches resource exhaustion.

Requested investigation

Please investigate:

  1. The refresh/invalidation loop behind

sidebar_workspace_task_groups_task_dirs.

  1. Whether Git-origin discovery is duplicated across multiple VS Code

extension hosts/windows.

  1. Whether repository results can be cached or concurrency/rate limited.
  2. Whether the internal sidebar Git/PR-origin functionality can be disabled

through a supported setting as a mitigation.

  1. Why uninstall/reinstall preserves or reconstructs the same historical

task-directory workload.

Sanitized measurements and command lines can be supplied. Full logs, ETL
traces, and live-kernel dumps exist but contain private workstation and
repository information and should not be uploaded publicly.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 1 month ago

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

  • #34854
  • #34548
  • #34672

Powered by Codex Action

tmesias · 1 month ago

019f7a38-8dd7-7982-a88a-e4423a600445

cxclrfx · 13 days ago

@tmesias — current Codex Desktop reproduction adds a strong Desktop-side coordinate to #35775

I reproduced the same Git-origin/process-storm family you documented in #35775, but on the current Microsoft Store Codex/ChatGPT Desktop application rather than the VS Code extension. The capture is long enough, and the parent/child topology is clean enough, that I think it adds a useful coordinate for narrowing the remaining root cause rather than simply adding another “Windows is slow” report.

This also intersects the Desktop work already reported in #29949, #26812, #34260, and #35880. I am writing this here because your requestKind=git-origins / source=sidebar_workspace_task_groups_task_dirs finding is the closest published coordinate I have seen to the behavior in this capture.

Environment

Observed on:

  • Windows x64, build 26200
  • Codex/ChatGPT Desktop package: OpenAI.Codex_26.810.4967.0_x64
  • Intel Core i5-14400F, 10 cores / 16 logical processors
  • 64 GB RAM
  • NVIDIA RTX 5060 Ti
  • normal local Git repository workspace
  • Git for Windows with Git Credential Manager
  • repository has a ChatGPT Sites remote, redacted here as:

https://git.chatgpt-team.site/<workspace>/<project>.git

The system was not memory constrained and the SSD was healthy. The user-visible symptom was system-wide cursor/UI stutter while Codex Desktop was active.

40-minute process trace

I ran a read-only 40.01-minute Windows process/performance capture while Codex Desktop was being used normally for local repository work.

System summary:

  • 1,349 system samples
  • average total CPU: 27.21%
  • maximum total CPU: 84%
  • maximum processor queue: 18
  • maximum DPC CPU: 5%
  • maximum interrupt CPU: 1%
  • nonpaged pool: 1,167.4–1,191.2 MB
  • paged pool: 2,703.7–3,003.4 MB

The important point is that this was not a classic sustained DPC/ISR storm or a RAM exhaustion event. The dominant abnormality was process churn.

Process starts in 40 minutes:

  • conhost.exe: 5,832
  • git.exe: 5,535
  • reg.exe: 3,221
  • node.exe: 289
  • pwsh.exe: 135
  • dllhost.exe: 135
  • tzutil.exe: 72
  • workerd.exe: 68
  • taskkill.exe: 54
  • gh.exe: 24
  • rg.exe: 22
  • cmd.exe: 19
  • codex-windows-sandbox-setup.exe: 13
  • git-remote-https.exe: 6
  • git-credential-manager.exe: 6
  • sh.exe: 6

Total process starts captured by the event trace: 15,563.

That is approximately 389 process starts/minute averaged over the whole run, or about 6.5 process creations/sec continuously averaged over 40 minutes.

The average hides much larger bursts.

Peak minute

At 23:30, the trace recorded:

  • 1,723 total process starts
  • 1,038 git.exe
  • 589 conhost.exe

Peak second

At 23:30:27, one single second contained 179 process starts:

  • 108 git.exe
  • 60 conhost.exe
  • 8 reg.exe
  • 1 pwsh.exe
  • 1 taskkill.exe
  • 1 svchost.exe

This is the point I would treat as the strongest process-scheduling “vibration”: the failure is not merely an aggressive periodic poll. At peak, many repository/process discovery operations are alive in parallel within one scheduler interval.

Parent topology: the Desktop main process is a primary source

The current app is packaged under OpenAI.Codex_26.810.4967.0.

The root Desktop process in the capture was:

ChatGPT.exe, PID 13856

The bundled app-server was a child:

ChatGPT.exe (13856)
-> codex.exe app-server

Over the 40-minute trace, PID 13856 directly created 5,832 children.

Direct children of the Desktop main PID:

  • reg.exe: 3,221
  • git.exe: 2,530
  • taskkill.exe: 54
  • gh.exe: 24
  • cmd.exe: 2
  • node.exe: 1

This matters because it narrows the origin of a large part of the storm to Desktop-shell/runtime behavior rather than the codex.exe app-server alone.

There are additional Git descendants below those direct children, which explains why total git.exe count reaches 5,535.

My strongest current hypothesis is therefore not “Git itself is slow.” It is that a Desktop-side state-refresh / metadata-discovery scheduler is producing redundant concurrent work, and the Windows subprocess model amplifies that work into system-wide latency.

A second coordinate that may be under-investigated: reg.exe

The git.exe / conhost.exe storm is already known. The new coordinate I would look at closely is the reg.exe volume:

3,221 reg.exe starts in 40 minutes.

All 3,221 were direct children of the Desktop main ChatGPT.exe PID in this capture.

That is too regular to dismiss as unrelated system noise.

I do not yet have the short-lived reg.exe command lines because the process-start ETW/WMI trace captured parent/PID/name, while command-line polling was too slow for sub-second children. I would specifically capture these command lines and the Desktop JS call site.

If you inspect the packaged runtime, I would search for:

  • reg.exe
  • registry/tool discovery wrappers
  • Git/GitHub CLI discovery
  • App Paths / executable lookup
  • environment or shell capability refresh
  • code paths that repeatedly re-check installed tools or registry state after workspace/chat/process updates

If the same refresh generation invokes both Git-origin discovery and registry/tool discovery, this could explain why the storm remains expensive even when only part of the Git path is suppressed.

ChatGPT Sites / Credential Manager is a real but separate branch

This repository has a local remote equivalent to:

sites -> https://git.chatgpt-team.site/<redacted>/<redacted>.git

and Git uses Credential Manager.

During the same 40-minute capture I observed six complete remote-authentication helper chains.

Representative chain:

ChatGPT.exe
-> git.exe
-> git.exe
-> git-remote-https.exe
-> sh.exe
-> git.exe
-> git-credential-manager.exe

The six GCM starts occurred approximately:

  • +16.8 s
  • +26.0 s
  • +53.1 s
  • +8 min 40.5 s
  • +10 min 40.3 s
  • +10 min 49.7 s

after diagnostic start.

This is consistent with #35880: background repository metadata discovery reaches a Sites HTTPS remote and invokes GCM even though the user did not request a fetch/pull/push operation.

I would keep this logically separate from the main 5,535-Git storm:

  • local Git-origin/repository probing explains thousands of process starts;
  • remote metadata discovery against a Sites remote explains the smaller number of git-remote-https / GCM chains and the visible credential prompt.

Fixing the GCM prompt alone will not fix the process storm.

Conversely, suppressing broad Git-origin probing may also eliminate the conditions that invoke GCM.

Important distinction from the empty-.git case

This capture is from a real Git repository, not only an invalid/empty .git placeholder.

So negative-caching invalid repositories is necessary for the empty-.git failure mode, but it is not sufficient for the general storm.

The current behavior also needs to be bounded for valid repositories and historical task/workspace directories.

That makes your #35775 coordinate particularly important:

requestKind=git-origins
source=sidebar_workspace_task_groups_task_dirs

The question I would now answer is:

What invalidates that request, and how many logically equivalent requests can coexist before the prior one completes?

Where I would instrument next

Rather than instrumenting Git itself, I would instrument the caller immediately above the worker/request boundary.

For every git-origins request, log only diagnostic metadata such as:

  • request generation/id
  • request source
  • invalidation reason
  • time since prior request
  • number of task directories supplied
  • number of canonicalized unique paths
  • number of unique Git common dirs
  • number of requests already in flight
  • cache hit/miss
  • negative-cache hit/miss
  • number of superseded requests cancelled
  • start/end duration
  • number of Git subprocesses spawned by that request

Then compare that with process creation.

If 100+ git.exe processes appear inside one second, I would expect to find one of these two shapes:

  1. one request fans out over a large, insufficiently deduplicated directory set; or
  2. several equivalent refresh generations overlap and each performs the same fan-out.

The second case would explain the very sharp burst shape better than a simple timer.

Specific runtime areas worth checking

The earlier #29949 investigation identified a packaged Git worker handling git-origins, plus separate WMI/process-discovery paths. In a newer build the minified filenames may have changed, so I would locate them by stable strings rather than by old minified export names.

Search the current app.asar / .vite/build payload for:

  • "git-origins"
  • "sidebar_workspace_task_groups_task_dirs"
  • Git-origin worker request handlers
  • rev-parse --show-toplevel
  • rev-parse --git-common-dir
  • config --get remote.origin.url
  • config --null --get core.fsmonitor
  • for-each-ref
  • remote show
  • reg.exe
  • taskkill.exe
  • Win32_Process
  • Win32_PerfFormattedData_PerfProc_Process

I would then map:

sidebar / thread / workspace invalidation
-> task-directory collection
-> canonicalization
-> git-origins request
-> worker fan-out
-> Git subprocess spawn

and separately:

command/process lifecycle
-> process/registry discovery
-> reg.exe / PowerShell / taskkill

The key is to identify whether these are independent periodic systems or whether one UI/workspace state mutation causes multiple discovery subsystems to refresh together.

Canonicalization boundary

For Git-origin discovery, deduplication should happen on repository identity, not only the raw task-directory string.

I would test canonicalization across:

  • path case differences on Windows
  • slash/backslash variants
  • task directories inside the same repository
  • Git worktrees sharing one common dir
  • historical thread cwd values
  • stale/missing task directories
  • nested directories inside one repository
  • duplicate workspace/thread references

A list containing 100 historical task directories should not produce 100 independent full Git-discovery sequences when most resolve to the same small set of repositories.

Possible stable cache key:

canonical Git common-dir + relevant config mtime/generation

rather than:

raw task cwd

Single-flight / cancellation boundary

The next concrete intervention I would test is:

  • one in-flight git-origins calculation per canonical repository set/generation;
  • coalesce identical requests;
  • cancel or ignore superseded generations;
  • bounded worker concurrency;
  • cache positive origin results;
  • negative-cache invalid/missing/non-Git paths;
  • no immediate retry loop for unchanged failure state.

The acceptance metric should be process creation proportional to unique repositories whose state actually changed, not proportional to sidebar refresh count, historical task count, or command lifecycle count.

Remote default-branch / Sites rule

Background UI metadata must not require network authentication.

For a sites / sites-origin HTTPS remote, ordinary sidebar/chat refresh should not invoke a networked git remote show.

If local metadata cannot establish the remote default branch, returning “unknown/not cached” is preferable to:

background UI refresh -> remote HTTPS -> GCM

The background path should use local Git config/refs only. A network operation should require an explicit user/agent action or an explicitly designed remote-refresh path.

A focused regression invariant would be:

Sending a normal chat message in a workspace containing a ChatGPT Sites remote must produce zero git-remote-https.exe and zero git-credential-manager.exe children unless a remote Git operation was explicitly requested.

taskkill.exe may be a feedback amplifier

This capture saw 54 taskkill.exe starts, all direct children of the Desktop main process.

That is not the dominant storm in this machine, but given #34260 I would check whether subprocess churn causes repeated cleanup work and whether slow cleanup then creates a secondary feedback loop.

For the cleanup boundary:

  • timeout every helper;
  • deduplicate cleanup for the same execution/PID tree;
  • global small concurrency cap;
  • backoff/circuit breaker when WMI/process enumeration is unhealthy;
  • prefer app-owned process tracking / Job Objects over repeated global process-tree discovery.

Controlled intervention matrix

To avoid conflating multiple Windows failure modes, I would run four isolated A/B interventions on the current build.

A — Git-origin scheduling only

Keep all other behavior unchanged.

Change only:

  • canonicalize/dedupe repository roots;
  • single-flight;
  • cache;
  • bounded concurrency;
  • cancellation of superseded refreshes.

Measure:

  • git.exe
  • conhost.exe
  • total process starts
  • input latency

B — network-free background remote metadata

Keep local origin discovery enabled.

Change only:

  • background default-branch/origin inspection cannot contact remote;
  • no remote show network path;
  • no GCM.

Expected result:

  • git-remote-https.exe = 0
  • git-credential-manager.exe = 0

during ordinary chat/sidebar activity.

This may not materially reduce the thousands of local Git starts, and that is useful separation.

C — registry/tool discovery

Keep Git behavior unchanged.

Suppress/cache only the Desktop path responsible for the repeated reg.exe starts.

Expected result:

  • direct reg.exe children collapse from thousands toward a small bounded number.

This would tell us whether registry discovery is another independent contributor to UI input pressure.

D — process cleanup

Keep A/B/C stock.

Bound only taskkill / tree cleanup.

Expected result:

  • no accumulation or overlapping cleanup helpers;
  • no WMI cleanup feedback loop.

Current-build regression value

The strongest reason I am posting this is that the failure family is still reproducible on:

OpenAI.Codex_26.810.4967.0_x64

That is substantially newer than the builds discussed in the June/July reports.

The earlier #29949 copied-runtime intervention was strong evidence that suppressing Desktop WMI/Git discovery could materially reduce input delay. This new capture shows that the current Desktop build can still enter an extremely high Git/console/registry process-creation regime.

So I would not treat the July findings as historical only.

What this trace does and does not prove

It proves:

  • severe short-lived process churn exists on this current Desktop build;
  • thousands of Git and console-host processes are created;
  • the Desktop main ChatGPT.exe is a direct parent of thousands of git.exe and reg.exe starts;
  • peak fan-out can reach 179 process creations in one second;
  • background remote/GCM chains still occur with a ChatGPT Sites remote;
  • the machine does not need to be RAM-starved or in a sustained DPC storm for the user-visible system stutter to occur.

It does not yet prove:

  • the exact JS invalidation call site in this current minified build;
  • that every reg.exe start belongs to the same refresh generation as git-origins;
  • exact per-event mouse latency because no manual lag markers were recorded in this run;
  • that the Sites/GCM branch is responsible for the bulk of the local Git storm.

Those are exactly the next points I would instrument rather than infer.

Suggested upstream acceptance tests

I would add Windows regression budgets at the product level:

  1. Idle valid repository
  • bounded, near-zero background Git process rate after initial discovery.
  1. 100 historical task directories resolving to 3 repositories
  • process count scales with 3 repositories, not 100 task directories.
  1. Repeated sidebar invalidation while one scan is in flight
  • no overlapping equivalent Git-origin fan-out.
  1. Invalid/empty .git
  • one failed detection followed by negative cache/backoff, not a tight retry loop.
  1. ChatGPT Sites remote present
  • ordinary chat/sidebar activity launches no git-remote-https and no GCM.
  1. Active local command traffic
  • no repeated global WMI/registry discovery per command lifecycle event.
  1. Windows input-latency budget
  • low-level mouse/keyboard delivery remains within a defined threshold during active repository work.
  1. Process-creation budget
  • no hundreds/thousands of short-lived Git/console processes per minute.

If useful, I can provide a sanitized table of process-start timestamps, parent PIDs and the 40-minute system summary. I would not publish the raw bundle unchanged because it contains local workstation/repository metadata.

I think the highest-yield place to look now is the Desktop-side invalidation/scheduling layer above git-origins, not Git for Windows itself: specifically how sidebar_workspace_task_groups_task_dirs (or its Desktop equivalent) is generated, deduplicated, invalidated, and allowed to overlap with prior generations. The 3,221 direct reg.exe starts are the second coordinate I would inspect in parallel because they suggest another Desktop refresh path may be participating in the same amplification.