Closed general

bridge_uninstall fails with Access is denied on a running exe bridge: stop the process first

John Lauer · 2mo ago ·closed by John Lauer

Measured on winvm (ab host, azureuser, 2026-09-08) during pup's fresh-install pre-production pass.

bridge_uninstall {name:"puppeteer"} returned remove cache dir: Access is denied. (os error 5) while the puppeteer bridge (the Rust adom-pup-bridge.exe, spawn.kind exe, persistent) was running. Windows will not delete a directory whose executable is loaded, so an uninstall of a persistent exe bridge fails unless the caller stopped the process first.

Ask: bridge_uninstall should stop the bridge it is uninstalling (the same stop path the respawn uses: stopMethod kill / killImageName from bridge.json, then wait for exit), then remove the cache dir, and report which of the two steps failed. Today the verb leaves the bridge running and the files in place, and the only way forward is a Tier-2 process_kill plus a shell delete, both approval-gated, which a fresh-box test cannot get through unattended.

Context: pup-bridge is preparing the Rust build for the public tier and needs an unattended "remove pup completely, reinstall as a new user" step on winvm.

1 Reply

John Lauer · 1mo ago

Fixed in insiders 2.1.134.

bridge_uninstall now stops the bridge before it touches the files, in the order you asked for:

  1. the bridge's own declared uninstall verb runs first (files still present, as before);
  2. the bridge is paused so the persistent supervisor cannot respawn it between the kill and the delete;
  3. the same stop path bridge_kill uses: tracked PIDs, then any orphan still bound to its runtime port matching killImageName; then a short wait for the port to be released;
  4. remove_dir_all, retried for ~3 s while Windows releases the exe handle;
  5. registry rescan; if a bundled copy remains it is un-paused (it keeps serving, as documented).

The reply says what happened: stopped: {attempted, killedPids}, cacheRemoved, failedAt: null | "remove", and the _hint no longer tells you to taskkill by hand.

Proof (arav-rog on 2.1.134, pup = adom-pup-bridge.exe, spawn.kind exe, persistent, running as pid 4892):

bridge_uninstall {name:"puppeteer"}   (4.4 s)
  success:true failedAt:null stopped:{attempted:true, killedPids:[4892]} cacheRemoved:true stillInstalledViaBundled:true
bridge_list after: puppeteer version 2.0.1 source bundled   (the installer seed took over, as documented)
bridge_install {manifestUrl: pup manifest}: success, version 2.0.601, source cache, running

So the unattended "remove pup completely, reinstall as a new user" step is one verb plus one bridge_install, no Tier-2 kill, no shell delete. Note for winvm: after the uninstall the bundled seed (2.0.1) answers until the reinstall lands, exactly as stillInstalledViaBundled:true says.

John Lauer closed this · 1mo ago

Log in to reply.