summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-13 15:40:06 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-13 15:40:06 +0200
commit78639260932dbd679d0de1f3132c645440962f46 (patch)
treee6acbfc0219167057eff9c99ddf54ebc5f610ad0 /packages/meshbay-node
parent600b698ab0cb9733dabf66f9528a6a868122c4f7 (diff)
downloadmeshbay-78639260932dbd679d0de1f3132c645440962f46.tar.gz
feat(node): keep the daemon alive when the hub rejects credentials
A node whose owner has not registered yet got a plain 401 from /v1/nodes/auth, which _login_with_retry re-raised — so the daemon exited and took its local admin UI down with it. That UI is where the operator reads the node's public key in order to link it, so exiting strands them: no daemon, no key, no way forward without digging the keystore open by hand. The daemon already parks on "No node key" for exactly this reason; it now parks on any 401, reporting waiting_for_account with a message naming the account and hub, and keeps retrying every 30s. The intended order remains: register on the hub, install the node, copy its key from the local UI, paste it into Settings > Link Node. The daemon now survives being started out of order instead of failing with a traceback. Adds QE/deploy/ — generic deployment (deploy-hub.sh, deploy-node.sh) kept separate from the demo scenario (demo.py, demo.env, README.md). Credentials live in QE/, which is gitignored; verified with git check-ignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node')
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py30
1 files changed, 22 insertions, 8 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index fa8c0ee..bedd2e9 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -390,14 +390,28 @@ class NodeDaemon:
return await hub.startup(endpoint_hint=None)
except _httpx.HTTPStatusError as e:
body = e.response.text if hasattr(e.response, 'text') else ''
- if e.response.status_code == 401 and "No node key" in body:
- self._state["status"] = "waiting_for_node_key"
- log.warning(
- "Node key not linked — open admin UI at "
- "http://localhost:%d, copy the key, and paste it in "
- "Settings > Link Node on the hub. Retrying in 30s...",
- self._config.node.ui_port,
- )
+ # Any 401 here needs a human at a browser, and the operator needs
+ # this daemon alive to read its public key out of the local admin
+ # UI. Exiting would take that UI down and strand them — which is
+ # exactly what happened when a node was started before its owner
+ # had registered.
+ if e.response.status_code == 401:
+ if "No node key" in body:
+ self._state["status"] = "waiting_for_node_key"
+ log.warning(
+ "Node key not linked. Open the admin UI, copy this "
+ "node's key, and paste it in Settings > Link Node on "
+ "%s. Retrying in 30s...",
+ self._config.hub.url,
+ )
+ else:
+ self._state["status"] = "waiting_for_account"
+ log.warning(
+ "Hub rejected the node credentials for user %r. "
+ "Register that account on %s first, then link this "
+ "node's key. Retrying in 30s...",
+ self._config.hub.username, self._config.hub.url,
+ )
await asyncio.sleep(30)
else:
raise