Repository navigation
Codex IDE sidebar Git-origin polling triggers severe Windows PID 4 Section-handle growth #35775
Description
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.fsmonitorgit -c core.hooksPath=NUL -c core.fsmonitor= rev-parse --abbrev-ref HEADgit -c core.hooksPath=NUL -c core.fsmonitor= remote
- Codex logs identified the repeating request as:
requestKind=git-originssource=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, andremotepattern. - 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:
- The refresh/invalidation loop behind
sidebar_workspace_task_groups_task_dirs. - Whether Git-origin discovery is duplicated across multiple VS Code
extension hosts/windows. - Whether repository results can be cached or concurrency/rate limited.
- Whether the internal sidebar Git/PR-origin functionality can be disabled
through a supported setting as a mitigation. - 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.
Activity
github-actions commentedon Jul 28, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
tmesias commentedon Jul 28, 2026
019f7a38-8dd7-7982-a88a-e4423a600445
cxclrfx commentedon Aug 14, 2026
@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_dirsfinding is the closest published coordinate I have seen to the behavior in this capture.Environment
Observed on:
OpenAI.Codex_26.810.4967.0_x64https://git.chatgpt-team.site/<workspace>/<project>.gitThe 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:
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,832git.exe: 5,535reg.exe: 3,221node.exe: 289pwsh.exe: 135dllhost.exe: 135tzutil.exe: 72workerd.exe: 68taskkill.exe: 54gh.exe: 24rg.exe: 22cmd.exe: 19codex-windows-sandbox-setup.exe: 13git-remote-https.exe: 6git-credential-manager.exe: 6sh.exe: 6Total 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:git.execonhost.exePeak second
At
23:30:27, one single second contained 179 process starts:git.execonhost.exereg.exepwsh.exetaskkill.exesvchost.exeThis 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 13856The bundled app-server was a child:
ChatGPT.exe (13856)-> codex.exe app-serverOver the 40-minute trace, PID 13856 directly created 5,832 children.
Direct children of the Desktop main PID:
reg.exe: 3,221git.exe: 2,530taskkill.exe: 54gh.exe: 24cmd.exe: 2node.exe: 1This matters because it narrows the origin of a large part of the storm to Desktop-shell/runtime behavior rather than the
codex.exeapp-server alone.There are additional Git descendants below those direct children, which explains why total
git.execount 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.exeThe
git.exe/conhost.exestorm is already known. The new coordinate I would look at closely is thereg.exevolume:3,221 reg.exestarts in 40 minutes.All 3,221 were direct children of the Desktop main
ChatGPT.exePID in this capture.That is too regular to dismiss as unrelated system noise.
I do not yet have the short-lived
reg.execommand 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.exeIf 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>.gitand 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.exeThe six GCM starts occurred approximately:
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:
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-
.gitcaseThis capture is from a real Git repository, not only an invalid/empty
.gitplaceholder.So negative-caching invalid repositories is necessary for the empty-
.gitfailure 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-originssource=sidebar_workspace_task_groups_task_dirsThe 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-originsrequest, log only diagnostic metadata such as:Then compare that with process creation.
If 100+
git.exeprocesses appear inside one second, I would expect to find one of these two shapes: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/buildpayload for:"git-origins""sidebar_workspace_task_groups_task_dirs"rev-parse --show-toplevelrev-parse --git-common-dirconfig --get remote.origin.urlconfig --null --get core.fsmonitorfor-each-refremote showreg.exetaskkill.exeWin32_ProcessWin32_PerfFormattedData_PerfProc_ProcessI would then map:
sidebar / thread / workspace invalidation-> task-directory collection-> canonicalization-> git-origins request-> worker fan-out-> Git subprocess spawnand separately:
command/process lifecycle-> process/registry discovery-> reg.exe / PowerShell / taskkillThe 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:
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/generationrather than:
raw task cwdSingle-flight / cancellation boundary
The next concrete intervention I would test is:
git-originscalculation per canonical repository set/generation;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-originHTTPS remote, ordinary sidebar/chat refresh should not invoke a networkedgit remote show.If local metadata cannot establish the remote default branch, returning “unknown/not cached” is preferable to:
background UI refresh -> remote HTTPS -> GCMThe 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.exeand zerogit-credential-manager.exechildren unless a remote Git operation was explicitly requested.taskkill.exemay be a feedback amplifierThis capture saw 54
taskkill.exestarts, 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:
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:
Measure:
git.execonhost.exeB — network-free background remote metadata
Keep local origin discovery enabled.
Change only:
remote shownetwork path;Expected result:
git-remote-https.exe = 0git-credential-manager.exe = 0during 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.exestarts.Expected result:
reg.exechildren 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:
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_x64That 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:
ChatGPT.exeis a direct parent of thousands ofgit.exeandreg.exestarts;It does not yet prove:
reg.exestart belongs to the same refresh generation asgit-origins;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:
Idle valid repository
100 historical task directories resolving to 3 repositories
Repeated sidebar invalidation while one scan is in flight
Invalid/empty
.gitChatGPT Sites remote present
git-remote-httpsand no GCM.Active local command traffic
Windows input-latency budget
Process-creation budget
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 howsidebar_workspace_task_groups_task_dirs(or its Desktop equivalent) is generated, deduplicated, invalidated, and allowed to overlap with prior generations. The 3,221 directreg.exestarts are the second coordinate I would inspect in parallel because they suggest another Desktop refresh path may be participating in the same amplification.tmesias commentedon Sep 2, 2026
I have a few additional data points from continued testing.
On my affected Windows workstation, the behavior now appears strongly tied to profile-local Codex/VS Code state rather than the machine, hardware, or workspace alone.
Control test:
AMUSCOLTDW11001P:\smm.011233Five-minute handle-only samples:
+4.269PID 4 handles/sec by regression-0.686PID 4 handles/sec by regression+0.046to+0.340handles/sec by regressionI then tested a mitigation on the affected profile:
%USERPROFILE%\.codex\sessionsout of the active profile and remove/updatesession_index.jsonl.session_index.jsonl.After that remove/restart/restore cycle, the affected profile's five-minute samples dropped materially. A recent sample with Codex open measured about
+0.480PID 4 handles/sec by regression, versus earlier material growth around+1.6to+4.3handles/sec and much older severe runs above+15handles/sec.This makes me suspect stale derived profile-local state, such as session/sidebar/project indexes generated from historical sessions, rather than the raw session JSONL files alone. The workaround is not proven permanent, but it may be a useful diagnostic/mitigation for others seeing persistent PID 4 handle growth on Windows.
Important caution: back up
%USERPROFILE%\.codex\sessionsandsession_index.jsonlbefore trying this. Do not delete local session history unless you are comfortable losing it.VijayAundhekar commentedon Sep 7, 2026
Independent IDE-extension reproduction with PoolMon and an empty
.gittriggerI reproduced this issue on a separate Windows workstation and can add a pool-tag coordinate plus a likely local trigger.
Environment
26200.92781.126.0openai.chatgpt@26.707.91948(win32-x64)Process-creation measurement
A fresh 10.23-second all-process CIM sample captured:
git.exeprocesses: approximately 287 total Git processes/minuteextension-hostPID 13720: approximately 188 direct launch chains/minuteRepresentative command:
code --statusindependently identified PID 13720 asextension-host [1]and showed the Codexcodex.exe ... app-serverbeneath that host.Kernel pool measurement
Across fresh PoolMon points from 13:45:36 through 15:05:41 local time (80.1 minutes):
Toke: 559.20 -> 801.99 MiB (+242.79 MiB, ~3.03 MiB/min, ~182 MiB/hour)SeAt+42.86 MiB,SeTd+16.07 MiB,SeTl+14.28 MiB,SeDt+11.73 MiBDuring the broader 88-minute window, user-mode commit fell by 6.89 GiB (mainly an ~8.08 GiB
vmmemWSLprivate-byte release), whileTokeand paged pool continued rising. No WHEA, bugcheck, Kernel-Power 41, resource-exhaustion, Docker OOM/restart, display, or NVIDIA event occurred. This isolates the growth from ordinary user-mode/WSL pressure.Exact empty
.gitfindingThe currently open VS Code workspace root contains an empty
.gitdirectory (0 entries).git rev-parse --show-toplevelreturns exit 128 there. A valid nested repository under that workspace has a normal non-empty.gitdirectory and resolves correctly.This strongly connects the IDE-extension reproduction here with the empty/invalid
.gitreproducer in #30926. The empty marker has not yet been renamed because the goal was first to preserve the live evidence and keep Codex continuously active. The next proposed intervention is a reversible rename of only that empty invalid.gitdirectory, without restarting VS Code or Codex, followed by the same Git-process and PoolMon measurements.Mitigation request
Official Codex IDE settings currently document no
chatgpt.*control for Git-origin discovery, polling interval, or sidebar historical-task-directory scanning. Please add a supported way to disable or bound background Git-origin discovery while leaving Codex chat/agent functionality active. Positive/negative caching, canonical repository-root deduplication, cancellation/single-flight, and a concurrency cap would also address this failure mode.No private repository paths, session contents, raw logs, or account data are included here. I can provide sanitized time series if a maintainer requests them.
Exact-version upstream match found
After posting the initial evidence, I found #28631, including this confirmation, on the exact same extension build
26.707.91948. That report traced the invalid-.gitwatcher loop and found that renaming the empty directory stopped repeatedrev-parseexecutions immediately without reloading VS Code or restarting the extension host. This makes the reversible invalid-marker rename the highest-value local A/B intervention here.Controlled live intervention result
The user then renamed only the empty invalid
.gitmarker while keeping VS Code, the extension host, and Codex app-server continuously running.git.exeprocesses in 10.23 seconds; 32 were direct extension-host children.git.exeprocesses in a 15.06-second all-process sample.codex.exePIDs/creation times remained unchanged, confirming no restart or disable occurred.Toke802.93 -> 803.29 MiB (+0.36 MiB/10 min) and total counter paged pool decreased 0.74 MiB. Earlier severe intervals were about +31 MiBTokeper 10 minutes. Because the pool slope had begun slowing before the rename, additional fresh points are being collected before attributing the pool change solely to the intervention.The immediate elimination of the Git loop without restarting Codex independently reproduces the workaround reported in #28631 on the same extension build.