{"record":{"id":"cae4e3af1590aefd","repo":"tinyhumansai/openhuman","slug":"transport-manager-all-transports-failed-to-conne","errorCode":null,"errorMessage":"[transport:manager] all transports failed to connect","messagePattern":"\\[transport:manager\\] all transports failed to connect","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/services/transport/TransportManager.ts","lineNumber":174,"sourceCode":"    const winner = await Promise.race([lanRace, tunnelRace]);\n\n    if (winner) {\n      // Close the losing transport.\n      void winner.loser.close().catch(() => {});\n      log('[transport:manager] race winner: %s', winner.transport.kind);\n      return winner.transport;\n    }\n\n    // Both failed in the race window — wait for whichever succeeds.\n    logErr('[transport:manager] race: both transports unhealthy; waiting…');\n    const result = await Promise.any([lanRace, tunnelRace]);\n    if (result) {\n      void result.loser.close().catch(() => {});\n      log('[transport:manager] fallback winner: %s', result.transport.kind);\n      return result.transport;\n    }\n\n    throw new Error('[transport:manager] all transports failed to connect');\n  }\n}\n\n// -- convenience factory ------------------------------------------------------\n\n/**\n * Build a TransportManager from a ConnectionProfile.\n * `localRpcUrl` / `localToken` are only needed for kind=\"local\".\n */\nexport function createTransportManager(\n  profile: ConnectionProfile,\n  opts: {\n    localRpcUrl?: () => Promise<string>;\n    localToken?: () => Promise<string | null>;\n    backendSocketUrl?: string;\n  } = {}\n): TransportManager {\n  const noop = () => Promise.resolve(null);","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/services/transport/TransportManager.ts#L156-L192","documentation":"Terminal state of raceLanAndTunnel: neither LAN (2s ping timeout) nor Tunnel answered openhuman.ping during the race window, and the Promise.any fallback wait also completed without a healthy transport. The desktop core is unreachable on every path this profile knows.","triggerScenarios":"A kind 'tunnel' (iOS/remote) profile where the device is off the LAN (or the core is not advertising LAN) AND the tunnel relay is unreachable or fails auth — LAN ping times out and the tunnel socket errors or never responds.","commonSituations":"Desktop app (and its in-process core) not running; device on cellular; backend socket relay down; invalid channelId/sessionToken so tunnel connect_error fires; firewall blocking the LAN RPC port.","solutions":["Confirm the desktop app and its core are running and the machine is awake","Check both paths: same Wi-Fi for LAN reachability, internet reachability for the tunnel relay (backendSocketUrl)","Call manager.reset() and retry — the race can be re-run once connectivity returns","If the tunnel socket reported connect_error, fix pairing/auth first (see tunnel profile errors)"],"exampleFix":"// before\nconst t = await manager.getTransport();\n\n// after\nlet t;\ntry {\n  t = await manager.getTransport();\n} catch (e) {\n  if (String(e.message).includes('all transports failed')) {\n    await manager.reset();\n    await sleep(2000);\n    t = await manager.getTransport(); // re-race LAN vs tunnel\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"retry","validationCode":"async function backendReachable(socketUrl: string): Promise<boolean> {\n  try {\n    await fetch(new URL('/health', socketUrl).toString(), { method: 'HEAD' });\n    return true;\n  } catch {\n    return false;\n  }\n}","typeGuard":null,"tryCatchPattern":"Catch 'all transports failed', call manager.reset(), wait a short backoff, then re-attempt getTransport() up to a small bound; after the bound, surface 'core unreachable' to the user rather than looping.","preventionTips":["Drive UI off the connectivity slice so RPC is only attempted when a path is plausible","Call manager.reset() on network change (Wi-Fi to cellular) instead of caching the failed transport","Confirm the desktop app/core is running before racing — the LAN leg cannot win otherwise"],"tags":["transport","tunnel","lan","connectivity","retry"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}