Open bug report

macOS: auto-update installs the Windows-only Rust build (adom-pup-bridge.exe) on Macs, so pup can't start (os error 13)

Drew Owens · 28d ago

On a Mac, auto-update replaced pup's working Node build with the Windows-only Rust build, and pup could not start at all. Every spawn failed with Permission denied (os error 13): 462 failed attempts before anyone noticed. Nothing told the user; the AI only saw a spawn error.

Mac: Apple Silicon, Adom Bridge managed by Hydrogen. Found 2026-10-13.

What was on the Mac

  • bridge_list: puppeteer 2.0.692, source: cache, entrypoint ~/Library/Application Support/Adom Bridge/bridges-cache/puppeteer/adom-pup-bridge.exe, spawn.kind: "exe".
  • That folder held only adom-pup-bridge.exe (8.4 MB), bridge.json, BRIDGE_VERSION, .bridge-version, and a leftover node_modules from the previous Node build (its server.js was gone).
  • pup_readiness: Failed to spawn bridge 'puppeteer': bridge 'puppeteer' is backing off after 462 failed spawn attempt(s): spawn failed: Permission denied (os error 13).
  • The release's own bridge.json says it shouldn't be there: platforms.macos.supported: false, "The Rust exe is Windows-only for now; host-mac is stubbed for the Mac port. macOS runs the Node build (public tier)."

Why it happens

  • adom-bridge-puppeteer-manifest.json publishes one platform: "any" zip per release (one url / sha256), so every OS gets the same artifact.
  • Since 2.0.401 ("pup as one Rust exe") every release is the Windows exe, except 2.0.601 ("Node shell for the public tier", promoted to public 2026-09-17), the last build a Mac can run.
  • The public manifest now points at 2.0.692, the exe. So the public channel has no Mac artifact, and any Mac that syncs gets a pup that can't start.

Workaround that worked

  1. bridge_uninstall {"name":"puppeteer"} removes the cache copy and falls back to the Node build bundled in the app (2.0.396, platforms.macos.supported: true).
  2. bridge_kill {"name":"puppeteer"} resets the spawn backoff. bridge_resume did not clear it, although the backoff error's hint says it does.
  3. pup_readiness → ready (Chrome for Testing 148, mac_arm).

Hours later the Mac is still on bundled 2.0.396 and pup works, but bridge_list reports latest: 2.0.692, so a later sync will likely put the exe back.

Asks

  1. Ship a macOS artifact with every public release: the Node shell (as in 2.0.601) or the Mac host build, as a per-platform asset (platform: macos) with a manifest that lets Adom Bridge pick by OS.
  2. Until then, keep Macs off the exe: a mac-specific updateManifestUrl, or a public manifest that points at a build that runs on both.
  3. Adom Bridge side (FYI, for whoever owns the updater): don't replace a working bridge with a release whose own bridge.json says the current platform is unsupported; and fix the spawn-backoff hint (or make bridge_resume actually clear the backoff).
  4. Minor: bundled 2.0.396 ignores the CLI's --ai-thread caller identity (pup_open_window → caller_identity_required), so callers on a Mac stuck on the bundled build must pass an explicit sessionId. One more reason to get Macs onto a current build.

Related: adom/nb-bridge#51 (nb has no macOS support yet).

Filed from Drew's Claude Code session (Drew's Mac, 2026-10-13).

5 Replies

Drew Owens · 28d ago

@kyle tagging you since this is macOS: the public channel has no Mac build, so every synced Mac gets the Windows exe and pup can't start. Drew's Mac is on the bundled 2.0.396 for now. Related nb macOS work: adom/nb-bridge#51.

John Lauer · 27d ago

Confirmed, and the cause is on pup's publishing side, not the Mac's. adom-bridge-puppeteer-manifest.json carries one platform: "any" zip per release, and since the Rust port that zip is the Windows exe. The public tier has pointed at the exe since 2.0.692, so any Mac that syncs gets a pup it cannot start. The last Mac-runnable build is 2.0.601 (Node).

Next step from the Windows side: a per-platform manifest, so Windows gets the Rust exe and macOS keeps a Node build it can run. Asked Kyle whether Adom Bridge supports per-platform entries in a bridge manifest, and whether he wants the Mac side here or in his own repo. Until this lands, a new public promotion would keep breaking Macs, so none goes out without it being called out.

Thanks for the workaround (bridge_uninstall, then bridge_kill to reset the backoff). The note that bridge_resume did not clear the backoff despite its hint is an Adom Bridge bug worth its own issue there.

Kyle Bergstedt · 27d ago

Status from Kyle's pup thread (2026-10-14).

Root cause confirmed, two halves. (1) The public manifest is one platform: "any" zip, the Windows exe since 2.0.692, and a Mac Bridge follows it blindly. (2) Even a Mac-runnable binary would have died the same way: Bridge's zip extraction wrote every file as mode 644, so a spawn.kind: "exe" entrypoint is never executable on macOS. "Permission denied (os error 13)" is that second half.

To John's question (per-platform entries): the bridge manifest format itself has no per-platform entries, but Adom Bridge for macOS has read a per-OS map in the bridge's own bridge.json since 1.9.212: updateManifestUrls: { "windows": <url>, "macos": <url> }, falling back to updateManifestUrl. So the split is one manifest file per platform, the way the KiCad bridge does it: your adom-bridge-puppeteer-manifest.json stays the Windows line and is untouched; a Mac follows adom-bridge-puppeteer-manifest-macos.json. 1.9.212 also refuses to install a zip whose bridge.json declares platforms.macos.supported: false, and 1.9.215 ranks such a cache copy below the bundled seed, so a Mac that already holds 2.0.692 falls back to the seed on its own.

What is done:

  • PR #3 on this page: the macOS build of the Rust pup (rust/host-mac implements the full Host trait; six trait methods with Windows-preserving defaults; the extension's captureVisibleTab bounded with the debugger fallback; tools/rust-build-macos.sh; the macOS manifest). Built as a universal, Developer ID signed binary; tools/parity.py goldens 55/56 against it on a Mac, plus the window verbs end to end with no focus steal.
  • Adom Bridge for macOS 1.9.217 (built, notarized, not yet published): restores the exec bit on extraction, and its bundled pup seed carries updateManifestUrls.macos pointing at the macOS manifest.

What is left, in order: upload adom-bridge-puppeteer-macos-v2.0.719.zip as the macos asset of release 2.0.719 (Kyle), merge or push the macOS manifest, publish Bridge 1.9.217. Until the Bridge ships, a Mac on 1.9.209 keeps Drew's workaround (bridge_uninstall {"name":"puppeteer"} + bridge_kill, back on the bundled 2.0.396 Node seed). Promotions of the Windows line stay safe for Macs once 1.9.217 is out, because the Mac never reads the Windows manifest again.

John Lauer · 27d ago

Kyle's PR #3 (the macOS build of the Rust pup) landed in 2.0.720 on insiders, with two fixes: the Windows workspace build had broken on the Mac crate, and a shell timeout did not end child processes. Details are on the PR. Public is 2.0.719 as of today.

Remaining for Macs, all on Kyle's side:

  • Upload adom-bridge-puppeteer-macos-v2.0.719.zip as the macos asset of release 2.0.719.
  • Push adom-bridge-puppeteer-manifest-macos.json.
  • Publish Adom Bridge for macOS 1.9.217.

Until then, a Mac uses Drew's workaround (bridge_uninstall {"name":"puppeteer"}, then bridge_kill).

Kyle Bergstedt · 21d ago

Update from Kyle's pup thread (2026-10-20). Thanks for landing #3 (2.0.720) and the guard (2.0.722); my tree is now rebased on the page repo at 2.0.729.

PR #5 (small, macOS-only, on top of 2.0.729): --use-mock-keychain on every Chrome launch — on a Mac, Chromium's OSCrypt otherwise creates a "Chromium Safe Storage" login-keychain item and the per-binary ACL pops "Google Chrome for Testing wants to use your confidential information…" on every new CfT build (seen on Kyle's Mac today, on a plain pup_open_window). Plus the depth-counted capture_unhidden() you asked for, and tools/rust-build-macos.sh is finally in the diff. The PR also carries adom-bridge-puppeteer-manifest-macos.json pointing at adom-bridge-puppeteer-macos-v2.0.729.zip built from that tree (sha256 17f16843…, 8427128 B).

Still Kyle-gated, unchanged: upload that zip as the macos asset of release 2.0.729, merge #5 (or push the manifest), publish Adom Bridge for macOS 1.9.219 (the exec-bit fix, updateManifestUrls.macos, and a duplicate-collapse fix on top of 1.9.217). Until then every release asset here is platform: any = the Windows exe, so a synced Mac keeps Drew's workaround.

Log in to reply.