Skip to content

Enrolled host-daemon has no collision handling for the default port (38887) when the desktop app is already running on the same machine #1121

Description

@Joesirven

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions