Problem
When a NIP-43 relay advertises no pairing_relay_url in its NIP-11 document, the desktop resolves the pairing endpoint through the legacy fallback: pairing_relay_from_nip11 (desktop/src-tauri/src/commands/pairing.rs:469) sees 43 in supported_nips and returns PairingRelay::LegacyPath, and resolve_pairing_relay_url (pairing.rs:452) appends /pair to the main relay URL.
If nothing serves that path (the state every compose deployment was in before #2736), the WebSocket upgrade 404s and the QR panel surfaces the raw transport error from pairing.rs:240:
WebSocket connection failed: HTTP error: 404 Not Found
That message names no URL, no route decision, and no config lever. Several self-hosters in #2734 independently had to source-dive config.rs and pairing.rs to discover that BUZZ_PAIRING_RELAY_URL (or routing /pair to a buzz-pair-relay sidecar) was the fix. @DrDoomi called out the diagnosability gap explicitly: #2734 (comment)
Suggested fix
The route decision is already a typed enum (PairingRelay, pairing.rs:411), so the connect error mapping at pairing.rs:238 can know which route failed. When the route is LegacyPath and the handshake fails with an HTTP status, emit something actionable instead of the bare transport error, along the lines of:
Pairing endpoint wss://<domain>/pair not found (404). The relay advertises
NIP-43 but no pairing_relay_url, and nothing is serving /pair. Set
BUZZ_PAIRING_RELAY_URL on the relay or route /pair to a buzz-pair-relay
instance (see deploy/compose/README.md, Device pairing).
Configured and MainRelay failures can keep the current message with the attempted URL appended, which also helps the split domain case when the configured URL is wrong.
Context
Follow-up to #2734. #2736 fixes the compose bundle so fresh deployments get a working /pair out of the box, but any deployment without a routed /pair or a configured pairing_relay_url still fails with the bare 404, and the error should say why.
Problem
When a NIP-43 relay advertises no
pairing_relay_urlin its NIP-11 document, the desktop resolves the pairing endpoint through the legacy fallback:pairing_relay_from_nip11(desktop/src-tauri/src/commands/pairing.rs:469) sees 43 insupported_nipsand returnsPairingRelay::LegacyPath, andresolve_pairing_relay_url(pairing.rs:452) appends/pairto the main relay URL.If nothing serves that path (the state every compose deployment was in before #2736), the WebSocket upgrade 404s and the QR panel surfaces the raw transport error from
pairing.rs:240:That message names no URL, no route decision, and no config lever. Several self-hosters in #2734 independently had to source-dive
config.rsandpairing.rsto discover thatBUZZ_PAIRING_RELAY_URL(or routing/pairto abuzz-pair-relaysidecar) was the fix. @DrDoomi called out the diagnosability gap explicitly: #2734 (comment)Suggested fix
The route decision is already a typed enum (
PairingRelay,pairing.rs:411), so the connect error mapping atpairing.rs:238can know which route failed. When the route isLegacyPathand the handshake fails with an HTTP status, emit something actionable instead of the bare transport error, along the lines of:ConfiguredandMainRelayfailures can keep the current message with the attempted URL appended, which also helps the split domain case when the configured URL is wrong.Context
Follow-up to #2734. #2736 fixes the compose bundle so fresh deployments get a working
/pairout of the box, but any deployment without a routed/pairor a configuredpairing_relay_urlstill fails with the bare 404, and the error should say why.