Describe the bug
On Windows, every gh invocation that records telemetry produces a brief console window flash. The flash is tzutil.exe /g being spawned by the gh send-telemetry subprocess to resolve the local IANA timezone (via the transitive dependency github.com/thlib/go-timezone-local).
With Windows Terminal configured to keep windows open after exit (e.g. closeOnExit: never / graceful), these conhost instances accumulate over time as orphan terminals.
gh --version output: gh version 2.81.0 (from C:\Program Files\GitHub CLI\gh.exe).
OS: Windows 11 Enterprise 10.0.26200.
Steps to reproduce the behavior
- On Windows, configure Windows Terminal default profile with
"closeOnExit": "never" (or use a setup that does not auto-close console windows on exit).
- Run any
gh command — for example gh pr list.
- Observe a brief console window flash. With the non-auto-close terminal config, the orphan window remains.
- Repeat — each
gh invocation produces another flash.
Tools that invoke gh periodically (e.g. VS Code GitHub extensions) cause this to occur every few minutes during normal use.
Expected vs actual behavior
Expected: gh send-telemetry runs as a fully headless background subprocess; no console window of any kind is visible to the user.
Actual: A tzutil.exe console window is briefly visible on every gh invocation that records telemetry.
Root cause
I traced the call chain by polling Win32_Process while running gh commands. Captured tree:
gh.exe (parent shell invocation)
└── gh.exe send-telemetry (spawned with DETACHED_PROCESS — no console)
└── tzutil.exe /g (allocates fresh conhost — visible flash)
internal/telemetry/detach_windows.go spawns the telemetry subprocess with DETACHED_PROCESS. gh send-telemetry then transitively invokes tzlocal.localTZfromTzutil() from github.com/thlib/go-timezone-local, which performs exec.Command("tzutil", "/g") with no Windows-specific window-suppression flags.
Per the Win32 process creation flags reference:
DETACHED_PROCESS — child has no console at all. Any console-subsystem descendant (tzutil.exe) then allocates a fresh conhost on first stdio access, producing the visible flash.
CREATE_NO_WINDOW — child runs as a console application without a visible console window. Descendants inherit the non-visible console and don't allocate a new one.
The two flags are mutually exclusive; for this use case CREATE_NO_WINDOW is the correct choice.
Suggested fix
Replace DETACHED_PROCESS with CREATE_NO_WINDOW in internal/telemetry/detach_windows.go. CREATE_NEW_PROCESS_GROUP remains compatible with the new flag, so Ctrl+C semantics for the detached telemetry child are preserved.
PR open: #13353.
Workaround
Setting DO_NOT_TRACK=1 in the user environment disables telemetry entirely, suppressing the spawn (and the flash) — at the cost of disabling telemetry that maintainers may legitimately want.
Describe the bug
On Windows, every
ghinvocation that records telemetry produces a brief console window flash. The flash istzutil.exe /gbeing spawned by thegh send-telemetrysubprocess to resolve the local IANA timezone (via the transitive dependencygithub.com/thlib/go-timezone-local).With Windows Terminal configured to keep windows open after exit (e.g.
closeOnExit: never/graceful), these conhost instances accumulate over time as orphan terminals.gh --versionoutput:gh version 2.81.0(fromC:\Program Files\GitHub CLI\gh.exe).OS: Windows 11 Enterprise 10.0.26200.
Steps to reproduce the behavior
"closeOnExit": "never"(or use a setup that does not auto-close console windows on exit).ghcommand — for examplegh pr list.ghinvocation produces another flash.Tools that invoke
ghperiodically (e.g. VS Code GitHub extensions) cause this to occur every few minutes during normal use.Expected vs actual behavior
Expected:
gh send-telemetryruns as a fully headless background subprocess; no console window of any kind is visible to the user.Actual: A
tzutil.execonsole window is briefly visible on every gh invocation that records telemetry.Root cause
I traced the call chain by polling
Win32_Processwhile running gh commands. Captured tree:internal/telemetry/detach_windows.gospawns the telemetry subprocess withDETACHED_PROCESS.gh send-telemetrythen transitively invokestzlocal.localTZfromTzutil()fromgithub.com/thlib/go-timezone-local, which performsexec.Command("tzutil", "/g")with no Windows-specific window-suppression flags.Per the Win32 process creation flags reference:
DETACHED_PROCESS— child has no console at all. Any console-subsystem descendant (tzutil.exe) then allocates a fresh conhost on first stdio access, producing the visible flash.CREATE_NO_WINDOW— child runs as a console application without a visible console window. Descendants inherit the non-visible console and don't allocate a new one.The two flags are mutually exclusive; for this use case
CREATE_NO_WINDOWis the correct choice.Suggested fix
Replace
DETACHED_PROCESSwithCREATE_NO_WINDOWininternal/telemetry/detach_windows.go.CREATE_NEW_PROCESS_GROUPremains compatible with the new flag, so Ctrl+C semantics for the detached telemetry child are preserved.PR open: #13353.
Workaround
Setting
DO_NOT_TRACK=1in the user environment disables telemetry entirely, suppressing the spawn (and the flash) — at the cost of disabling telemetry that maintainers may legitimately want.