Describe the bug
Running copilot in a terminal can silently break the GitHub Copilot desktop app. Afterwards the app cannot resume any existing session — every one fails with "Session unavailable — We couldn't reconnect to your session." Nothing in the app suggests the CLI is involved, and no session data is damaged.
The cause is that the auto-updater rewrites the copilot.exe it was launched from, in place. The desktop app pins its bundled engine by directory name (%LOCALAPPDATA%\github-copilot-sdk\cli\<version>\copilot.exe) and probes its version exactly once, at startup. When an unrelated invocation of that same binary auto-updates, the directory keeps its old version name while holding a newer build — and the app is left driving an engine whose RPC surface it no longer speaks.
The app cannot defend itself against this. It already launches the CLI with --no-auto-update; the damage is done by a different invocation, and the app has no way to know the file changed underneath it.
Frequency: deterministic. Once the binary is replaced, 100% of session resumes fail until it is restored.
Extensions: not a factor. Extensions do launch, then die as a consequence (peer-closed-before-ready, exit code=1) when the host tears the session down after the failed RPC.
Affected version
|
|
| CLI after the auto-update |
1.0.83-5 |
| CLI the app had pinned |
1.0.80 |
| GitHub Copilot desktop app |
1.1.14 |
The incompatibility itself is introduced somewhere in 1.0.81 — see the related issue below.
Steps to reproduce
- Install the GitHub Copilot desktop app (
1.1.14). It bundles CLI 1.0.80 at %LOCALAPPDATA%\github-copilot-sdk\cli\1.0.80\copilot.exe.
- Start the app. It probes and records that binary once:
INFO github_app::platform::health: Detected Copilot CLI version at startup
version=Copilot binary version: 1.0.80 source=Some(Bundled)
path="%LOCALAPPDATA%\github-copilot-sdk\cli\1.0.80\copilot.exe" bundled_version="1.0.80"
- From any other context, run that same
copilot.exe without --no-auto-update (auto-update is on by default). In my case this was an ordinary terminal session — the CLI log shows "client_name": "github/cli", so it was not the app.
- Observe the updater replace the binary in place, preserving the old one alongside it:
[INFO] Successfully downloaded package, restart to update to version 1.0.83-5
[INFO] Downloading updated win32-x64 binary...
The folder now contains copilot.exe (the new build) and copilot.exe.old-<pid>-<timestamp> (the original). The folder is still named 1.0.80.
- In the app, open any existing session.
- Observe "Session unavailable — We couldn't reconnect to your session."
Expected behavior
Auto-update should not rewrite a binary it did not install — or at minimum should not leave a versioned directory asserting a version its contents no longer are.
Additional context
Environment
App version 1.1.14
OS Windows 10 Enterprise 25H2 (build 26200.9106)
Architecture AMD64
WebView2 runtime 152.0.4191.62
Copilot CLI 1.0.80 (after manual rollback; was 1.0.83-5 at failure)
Agency 2026.9.3.7
GPU 0 Intel(R) Graphics (32.0.101.8132)
GPU 1 NVIDIA GeForce RTX 5090 (32.0.16.1656)
WebView2 flags --disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection,CalculateNativeWinOcclusion,UiaProvider,AccessibilityBlockFlowIterator
--force-renderer-accessibility
Related: github/app#3284 reports the same resume failure, but reached it deliberately via COPILOT_CLI_PATH — so that reporter could simply remove the override. This issue is the path with no opt-out: the bundled binary is the one replaced, so the documented fallback ("use the bundled CLI") is exactly what's broken. That issue is also filed on the app tracker, though the RPC surface is engine-owned, which may be why it hasn't been triaged.
Workaround (verified): set COPILOT_AUTO_UPDATE=false, then restore the preserved copilot.exe.old-<pid>-<timestamp> over copilot.exe. With the variable set, each launcher resolves its own built-in payload instead of the newest cached one, so independent installs stop interfering.
Suggested labels: whichever area:* covers packaging/updates, plus area:sessions for the user-visible symptom.
In-depth investigation
The failing call. The engine resumes fine; the app then makes one more call and gives up:
INFO github_app::session::core: CLI session resumed
INFO github_app::session::core: session resume flow completed
WARN github_app::handlers::session: failed to resume session
error=RPC error -32601: Unhandled method session.permissions.getAllowAll
What changed. Extracting session.permissions.* method strings from each engine's app.js:
| Engine |
Methods exposed |
1.0.80 |
14 — incl. getAllowAll, setAllowAll, setApproveAll, configure |
1.0.83-5 |
1 — setMode |
The app binary (1.1.14) contains 4 references to permissions.getAllowAll and zero to permissions.setMode, so it cannot drive the newer engine at all.
Why --no-auto-update doesn't save you. From the SEA loader, resolution order is: --prefer-version → COPILOT_CLI_DIST_DIR → (auto-update on) newest downloaded pkg → (auto-update off) the binary's built-in version. So --no-auto-update pins to the binary file, not to a version number — which is precisely why replacing the file defeats it. Demonstrated on the same machine:
| Invocation |
Reports |
1.0.80 binary + --no-auto-update |
1.0.80 |
1.0.80 binary, bare --version |
1.0.83-5 |
1.0.83-5 binary + --no-auto-update |
1.0.83-5 |
Note the middle row: --version alone is misleading, because auto-update is on for that invocation. --binary-version is the honest discriminator.
This is chronic. Agency keeps an update-check cache keyed by <path>|<version>. Decoding the entries for the app's single pinned path shows it has held at least five different builds:
…\cli\1.0.80\copilot.exe | 1.0.79
…\cli\1.0.80\copilot.exe | 1.0.80
…\cli\1.0.80\copilot.exe | 1.0.81-3
…\cli\1.0.80\copilot.exe | 1.0.82
(plus 1.0.83-5, the one that finally broke it). There is also a leftover cli\1.0.71\.copilot-update-<timestamp>\ staging directory from an earlier in-place update. The behaviour is long-standing; it only became visible when 1.0.81 removed the RPC method.
Blast radius. Only sessions needing a fresh engine process are affected — already-running ones keep the old mapped image and work normally. That makes it look intermittent, and it means restarting the app converts one broken session into all of them.
Describe the bug
Running
copilotin a terminal can silently break the GitHub Copilot desktop app. Afterwards the app cannot resume any existing session — every one fails with "Session unavailable — We couldn't reconnect to your session." Nothing in the app suggests the CLI is involved, and no session data is damaged.The cause is that the auto-updater rewrites the
copilot.exeit was launched from, in place. The desktop app pins its bundled engine by directory name (%LOCALAPPDATA%\github-copilot-sdk\cli\<version>\copilot.exe) and probes its version exactly once, at startup. When an unrelated invocation of that same binary auto-updates, the directory keeps its old version name while holding a newer build — and the app is left driving an engine whose RPC surface it no longer speaks.The app cannot defend itself against this. It already launches the CLI with
--no-auto-update; the damage is done by a different invocation, and the app has no way to know the file changed underneath it.Frequency: deterministic. Once the binary is replaced, 100% of session resumes fail until it is restored.
Extensions: not a factor. Extensions do launch, then die as a consequence (
peer-closed-before-ready,exit code=1) when the host tears the session down after the failed RPC.Affected version
1.0.83-51.0.801.1.14The incompatibility itself is introduced somewhere in
1.0.81— see the related issue below.Steps to reproduce
1.1.14). It bundles CLI1.0.80at%LOCALAPPDATA%\github-copilot-sdk\cli\1.0.80\copilot.exe.copilot.exewithout--no-auto-update(auto-update is on by default). In my case this was an ordinary terminal session — the CLI log shows"client_name": "github/cli", so it was not the app.copilot.exe(the new build) andcopilot.exe.old-<pid>-<timestamp>(the original). The folder is still named1.0.80.Expected behavior
Auto-update should not rewrite a binary it did not install — or at minimum should not leave a versioned directory asserting a version its contents no longer are.
Additional context
Environment
Related: github/app#3284 reports the same resume failure, but reached it deliberately via
COPILOT_CLI_PATH— so that reporter could simply remove the override. This issue is the path with no opt-out: the bundled binary is the one replaced, so the documented fallback ("use the bundled CLI") is exactly what's broken. That issue is also filed on the app tracker, though the RPC surface is engine-owned, which may be why it hasn't been triaged.Workaround (verified): set
COPILOT_AUTO_UPDATE=false, then restore the preservedcopilot.exe.old-<pid>-<timestamp>overcopilot.exe. With the variable set, each launcher resolves its own built-in payload instead of the newest cached one, so independent installs stop interfering.Suggested labels: whichever
area:*covers packaging/updates, plusarea:sessionsfor the user-visible symptom.In-depth investigation
The failing call. The engine resumes fine; the app then makes one more call and gives up:
What changed. Extracting
session.permissions.*method strings from each engine'sapp.js:1.0.80getAllowAll,setAllowAll,setApproveAll,configure1.0.83-5setModeThe app binary (
1.1.14) contains 4 references topermissions.getAllowAlland zero topermissions.setMode, so it cannot drive the newer engine at all.Why
--no-auto-updatedoesn't save you. From the SEA loader, resolution order is:--prefer-version→COPILOT_CLI_DIST_DIR→ (auto-update on) newest downloaded pkg → (auto-update off) the binary's built-in version. So--no-auto-updatepins to the binary file, not to a version number — which is precisely why replacing the file defeats it. Demonstrated on the same machine:--no-auto-update1.0.80--version1.0.83-5--no-auto-update1.0.83-5Note the middle row:
--versionalone is misleading, because auto-update is on for that invocation.--binary-versionis the honest discriminator.This is chronic. Agency keeps an update-check cache keyed by
<path>|<version>. Decoding the entries for the app's single pinned path shows it has held at least five different builds:(plus
1.0.83-5, the one that finally broke it). There is also a leftovercli\1.0.71\.copilot-update-<timestamp>\staging directory from an earlier in-place update. The behaviour is long-standing; it only became visible when1.0.81removed the RPC method.Blast radius. Only sessions needing a fresh engine process are affected — already-running ones keep the old mapped image and work normally. That makes it look intermittent, and it means restarting the app converts one broken session into all of them.