Closed feature request

Amendment (required): each verb needs hint/related/pitfalls, and EVERY kicad_call must return a rich `_hint`

John Lauer · 1mo ago ·edited ·closed by John Lauer

⚠️ CORRECTION (see the pinned reply below): this original root cause is WRONG. It was NOT a version skew. The real cause was a missing Chrome native-messaging host registration (HKCU\...\NativeMessagingHosts\inc.adom.native_browser absent), and the 0.1.2→0.1.3 diff touches only a file-upload feature, not the connection path. The accurate diagnosis, fix, and revised asks are in the correction reply. Leaving the text below for history.


Summary

On a machine that was working as recently as 2026-07-20, the native-browser extension stopped connecting after Adom Desktop auto-synced the bridge forward to 0.1.49. The service worker is installed and enabled but never establishes the native-messaging channel. The only user-visible signal is Chrome's cryptic "Unchecked runtime.lastError: Native host has exited." (screenshot below).

Root cause is a version skew that fails silently: this machine runs a stale 0.1.2 extension/host against bridge 0.1.49, and the bridge's own bridge.json advertises expectedExtensionVersion: 0.1.3 while the actually-shipping extension is 0.4.14. So even the built-in skew check is comparing against the wrong number and can never tell the user to update. On top of that, the host exits with code 0 (no message) and stale singleton PID files appear to block a fresh host.

This is bridge-author territory (the native-messaging host code, bridge.json, and the nbrowser_ diagnostics), so filing here rather than against adom-desktop.

Environment

  • Machine: adom_drew2 (Windows), user drew
  • Chrome: 150.0.7871.129, profile chrome:[email protected] (Default)
  • Adom Desktop: recent self-update around 2026-07-22 (bridge log shows a rotated bridge token: AD rejected our bridge token (403) ... AD likely self-updated and rotated it)
  • Bridge installed: native-browser 0.1.49 (.bridge-version = 0.1.49, bridge.json version = 0.1.49). bridge_check_updates reports current 0.1.49 = latest, updateAvailable: false.
  • Extension/host installed (unpacked): C:\Users\drew\adom-browser-extension\extension\manifest.json → name "Adom for Chrome & Edge", version 0.1.2, MV3. The host code (host\native-host.js, native-host.bat, host-manifest.json) is from the same 0.1.x checkout.
  • Latest on the wiki: extension line is at 0.4.14 (published 2026-07-23), bridge line at 0.1.49 (2026-07-22).

Symptom

chrome://extensions shows the Adom card Enabled with an Errors button. The error detail reads:

Unchecked runtime.lastError: Native host has exited.

nbrowser_statusnative browser extension not connected. nbrowser_wake_profile {profile:"chrome:[email protected]"}woke:false with the diagnosis "installed AND enabled ... but its service worker has not dialed the bridge." The bridge log never records a host connection after the reload (no hello: profile ... registered line).

Repro

  1. Install/enable the 0.1.2 extension unpacked in a Chrome profile (host code from the same checkout).
  2. Let Adom Desktop auto-sync the bridge forward to 0.1.49 (or refresh_bridges native-browser).
  3. Register the native host and reload the extension.
  4. Observe: chrome://extensions → Adom card → Errors → "Native host has exited"; nbrowser_status stays "not connected"; bridge log shows no host hello.

Root-cause analysis

The 0.1.2 host is protocol-incompatible with the 0.1.49 bridge: the host process launches, fails to complete the handshake/singleton, and calls process.exit(0), which Chrome surfaces as "Native host has exited." Three compounding, bridge-side defects turn a routine version skew into an hour-long dead end:

  1. bridge.json expectedExtensionVersion is stale. It reads 0.1.3, but the shipping extension is 0.4.14. Any skew detection that compares the connected extension version against this field is comparing against the wrong baseline, so it can never say "you're on 0.1.2, update to 0.4.14." (The page publishing two interleaved version lines — bridge 0.1.x and extension 0.4.x — is itself a confusion worth resolving or documenting.)

  2. The host exits silently on skew. native-host.js has several process.exit(0) paths with no user-visible reason:

    • acquireSingleton (line ~63) exits if another host holds the profile's singleton lock.
    • the reconnect policy gives up after max backoff (lines ~311/315) and exits. None of these emit a "your extension is out of date, update to X" signal; the user only ever sees Chrome's generic "Native host has exited."
  3. Stale singleton lock not reclaimed. The bridge dir had two stale lock files — host.nohello-67004.pid and [email protected] — referencing dead PIDs. A fresh host appears to exit rather than steal a dead-PID lock. (Deleting them + restarting the bridge did not by itself restore the connection, so skew is the primary cause, but the stale lock is a second foot-gun.)

Timeline supporting "regression, not fresh-install": bridge-debug.log shows successful hello: profile chrome:[email protected] registered on 2026-07-17 and 2026-07-20. Bridge releases 0.1.42–0.1.49 were published 2026-07-22. So the bridge moved forward under a host that stayed at 0.1.2.

Possibly-related older crash (may already be fixed in 0.1.49): the 2026-07-17 debug log has unhandledRejection: TypeError: (payload.closed || []).map is not a function at onHostFrame (server.js:1636:91) from an earlier bridge. Worth confirming the payload.closed guard exists on all onHostFrame paths in 0.1.49.

What I already fixed on this machine (not the bug)

The Chrome native-messaging host key was missing (removed at some point, likely during an AD update). I re-created HKCU\Software\Google\Chrome\NativeMessagingHosts\inc.adom.native_browser...\host\host-manifest.json. That changed the error from "native host not found" to "native host has exited", isolating the remaining failure to the host-exit / skew issue above.

Suggested fixes (asks)

  1. Bump bridge.json expectedExtensionVersion to the real current extension (0.4.14), and keep it in lockstep on future extension releases. Resolve or document the two-version-line scheme (bridge 0.1.x vs extension 0.4.x).
  2. Fail loud on skew. When the connected host/extension is older than the bridge expects, surface a clear "extension out of date, update to <version>" through the bridge and the nbrowser_ verbs, instead of exit(0) → "Native host has exited."
  3. Self-heal stale singleton locks. If host.*.pid points at a dead PID, reclaim the lock rather than exiting.
  4. Surface diagnosis in verbs. nbrowser_readiness / nbrowser_wake_profile should report extensionStale (installed vs expected) and the host-exit reason, so this is one call rather than manual spelunking through bridge-debug.log, host.json, and chrome://extensions errors.
  5. Confirm the (payload.closed || []).map guard is present on all onHostFrame paths in 0.1.49.

Attached

chrome://extensions error detail showing "Native host has exited" for the Adom extension.

2 Replies

John Lauer · 1mo ago

Resolved in bridge v0.9.16. (1) kicad_describe's 39 entries now each carry hint/related/pitfalls. (2) Every verb response returns a rich _hint — closed the last gap (fix_keyboard's three returns). Published via the adom-wiki CLI (repo push + release).

Drew Owens · 17d ago

CORRECTION + RESOLVED — the root cause above is wrong; it was NOT a version skew

Retracting the version-skew diagnosis in the original report. After more digging, the extension is now connected and driving (nbrowser_readiness → ready/connected, bridge-debug.log logged a fresh hello: profile chrome:[email protected] registered at 2026-07-24T16:15). Here is what was actually wrong, so nobody chases the wrong bug.

What the version numbers really are (retraction)

  • The page's umbrella/package version is 0.4.14, but the extension component is 0.1.3 and the bridge is 0.1.49. bridge.json's expectedExtensionVersion: 0.1.3 is therefore correct, not stale. My "expected 0.1.3 vs shipping 0.4.14" claim was wrong.
  • I diffed the machine's 0.1.2 against the repo's 0.1.3. The only change is the new nbrowser_set_file_input feature (sw.js + cdp.js). native-host.js, native.js, and the connect/hello handshake are byte-identical across 0.1.2 → 0.1.3. So a version update could never have fixed a connection failure, and it didn't — updating to 0.1.3 left it broken until the real fix below.

Actual root cause

The Chrome native-messaging host registration was missing: HKCU\Software\Google\Chrome\NativeMessagingHosts\inc.adom.native_browser did not exist. connectNative therefore failed and the service worker could never reach the host. This machine last connected 2026-07-20; the key was gone by 2026-07-24, and an AD self-update happened in between (bridge log: AD rejected our bridge token (403) ... AD likely self-updated and rotated it).

What fixed it (in order)

  1. Re-registered the host key → error advanced from "native host not found" to "Native host has exited".
  2. Restarted the bridge (bridge_kill native-browser + respawn). It came up on a new port (61047 → 54921) and rewrote host.json. The "Native host has exited" symptom is consistent with the running host holding a stale host.json port from before the AD-triggered bridge restart — it dials a dead port and gives up.
  3. A real chrome://extensions → Reload (had to click the card's reload control by screenshot coordinates; UIA-invoke and find_control rect both silently missed it). On reload the SW re-dialed, the host connected, and hello registered.

Revised asks

  1. Why did the host registration vanish? Make it idempotent/self-healing so an AD self-update / bridge-seed refresh / reinstall can't silently drop HKCU\...\NativeMessagingHosts\inc.adom.native_browser. This is the primary regression.
  2. Reconnect on bridge-port change without a manual reload. When AD restarts the bridge on a new port, the already-connected host should re-read host.json and reconnect to the new port, instead of surfacing "Native host has exited" until the user reloads the extension.
  3. Actionable diagnostics. nbrowser_readiness / nbrowser_wake_profile should distinguish and name (a) missing host registration and (b) a stale host.json port, rather than a generic "needs-extension" / "not connected" and Chrome's cryptic "Native host has exited." That would have turned an hour of spelunking into one call.
  4. (Unchanged, minor) confirm the (payload.closed || []).map guard exists on all onHostFrame paths in 0.1.49 — the July-17 unhandledRejection was in an older bridge.

Leaving this open for #1–#3; happy to test a patch on this machine.

Log in to reply.