Workflow
Machine already running the packaged desktop app (bb.app), which runs its own local server + host-daemon for "This Mac" as its primary host. Used Settings → Machines → Add machine on a different, remote bb server to enroll this same Mac as an additional execution host (installed via /install.sh ... --join-code ... --host-id ... --server ..., which sets up a separate launchd service for the new host-daemon, pointed at the remote server).
What happened
The installer printed a failure at the very end, after the npm install and the join API call both succeeded:
Joining http://<remote-server>:38886 as host_xxxxxxxxx...
Joined successfully.
Could not find service "app.getbb.host-daemon.<label>" in domain for user gui: 501
(exit code 113). That "Could not find service" text is launchctl's own native error text, not a bb-authored message — the installer shells out to launchctl to verify the service came up and surfaces whatever it says.
The actual root cause: the desktop app's own host-daemon was already bound to 127.0.0.1:38887 (the fixed default host-daemon port, hardcoded regardless of which server a given daemon is enrolled to). The newly-created launchd service for the remote-server enrollment tried to bind the same port, hit EADDRINUSE, and crashed:
Error: listen EADDRINUSE: address already in use 127.0.0.1:38887
at Server.setupListenHandle [as _listen2] (node:net:2167:16)
launchd's KeepAlive then restarted it in a loop. The installer's own post-bootstrap launchctl check happened to run during one of the crashed windows, producing the confusing "Could not find service" text — but even after that, the daemon kept silently crash-looping forever: it can never win the race for port 38887 while the desktop app's own daemon holds it permanently. The remote server's hosts table showed the new host as enrolled (the join API call had already succeeded), but its host_daemon_sessions table never got a row for it, and last_seen_at stayed null indefinitely — the remote server's UI correctly showed the machine as offline, with no error surfaced anywhere pointing at the actual port conflict.
Fixed manually by editing the generated plist to add --host-daemon-port <alternate-port> (a flag bb-app host-daemon already supports) and reloading via launchctl bootout/bootstrap. After that the session appeared immediately.
Expected
- The installer/
host-daemon process should detect EADDRINUSE on its own default port and either auto-select a free port or fail with a clear, actionable message ("port 38887 already in use by another bb host-daemon — pass --host-daemon-port to use a different one"), instead of crash-looping silently under launchd.
- The "Add machine" installer shouldn't report a bare
launchctl error as if it were bb's own diagnostic; it should distinguish "service didn't register" from "service is crash-looping" and say which.
This will affect anyone who enrolls a machine that's already running the desktop app locally on the same box — plausibly a common setup, not an edge case.
Environment
- bb-app 0.35.1
- macOS 26.3, Apple Silicon, launchd
Workflow
Machine already running the packaged desktop app (
bb.app), which runs its own local server + host-daemon for "This Mac" as its primary host. Used Settings → Machines → Add machine on a different, remote bb server to enroll this same Mac as an additional execution host (installed via/install.sh ... --join-code ... --host-id ... --server ..., which sets up a separatelaunchdservice for the new host-daemon, pointed at the remote server).What happened
The installer printed a failure at the very end, after the npm install and the join API call both succeeded:
(exit code 113). That "Could not find service" text is
launchctl's own native error text, not a bb-authored message — the installer shells out tolaunchctlto verify the service came up and surfaces whatever it says.The actual root cause: the desktop app's own host-daemon was already bound to 127.0.0.1:38887 (the fixed default host-daemon port, hardcoded regardless of which server a given daemon is enrolled to). The newly-created
launchdservice for the remote-server enrollment tried to bind the same port, hitEADDRINUSE, and crashed:launchd'sKeepAlivethen restarted it in a loop. The installer's own post-bootstraplaunchctlcheck happened to run during one of the crashed windows, producing the confusing "Could not find service" text — but even after that, the daemon kept silently crash-looping forever: it can never win the race for port 38887 while the desktop app's own daemon holds it permanently. The remote server'shoststable showed the new host as enrolled (the join API call had already succeeded), but itshost_daemon_sessionstable never got a row for it, andlast_seen_atstayed null indefinitely — the remote server's UI correctly showed the machine as offline, with no error surfaced anywhere pointing at the actual port conflict.Fixed manually by editing the generated plist to add
--host-daemon-port <alternate-port>(a flagbb-app host-daemonalready supports) and reloading vialaunchctl bootout/bootstrap. After that the session appeared immediately.Expected
host-daemonprocess should detectEADDRINUSEon its own default port and either auto-select a free port or fail with a clear, actionable message ("port 38887 already in use by another bb host-daemon — pass --host-daemon-port to use a different one"), instead of crash-looping silently underlaunchd.launchctlerror as if it were bb's own diagnostic; it should distinguish "service didn't register" from "service is crash-looping" and say which.This will affect anyone who enrolls a machine that's already running the desktop app locally on the same box — plausibly a common setup, not an edge case.
Environment