tinyhumansai/openhuman · critical
[transport:manager] all transports failed to connect
Error message
[transport:manager] all transports failed to connect
What it means
raceLanAndTunnel() first races LAN isHealthy (2s LAN_RACE_TIMEOUT_MS) against tunnel isHealthy; when both resolve null it awaits Promise.any for a late winner, and if that also yields null it gives up: neither the LAN HTTP ping nor the tunnel handshake ever succeeded. This is the terminal 'no path to the core' error for tunnel profiles.
Solutions
- Call manager.reset() and retry once — the doc comment explicitly designs reset() for re-racing after a winner later failed
- Verify the desktop core is running and on the same network, then retry while on LAN
- Check tunnel credentials (re-pair if the session was revoked) via the error surfaced by the losing tunnelRace
- Fall back to another profile (local on the desktop itself, or cloud) until connectivity returns
Example fix
// before
const t = await manager.getTransport();
// after
let t;
try {
t = await manager.getTransport();
} catch (err) {
manager.reset();
t = await manager.getTransport(); // re-race LAN vs Tunnel once
} Defensive patterns
Strategy: retry
Validate before calling
// Cheap reachability split before the expensive race:
async function lanReachable(rpcUrl: string): Promise<boolean> {
try { await fetch(rpcUrl, { method: 'HEAD' }); return true; } catch { return false; }
} Try / catch
try {
return await manager.getTransport();
} catch (err) {
if (err instanceof Error && err.message.includes('all transports failed')) {
manager.reset(); // documented recovery: re-race LAN vs Tunnel
await sleep(2_000);
return await manager.getTransport();
}
throw err;
} Prevention
- Call manager.reset() before re-racing — a previously-won-but-dead transport is cached otherwise
- Retry only a bounded number of times, then fall back to another profile
- Log which transport won previously; a LAN winner that later died is the designed reset() case
When it happens
Trigger: Desktop host unreachable on LAN (asleep, off, IP changed) AND the backend relay rejecting the tunnel (invalid/expired sessionToken, channel closed) or the relay itself down; both transports' openhuman.ping health checks failing.
Common situations: Remote usage where the home machine is off; device session revoked while also off-LAN; backend outage; firewall blocking both the LAN port and websocket egress.
Related errors
- LAN RPC returned an error
- [transport:lan] HTTP
- [transport:lan] timed out after ms
- [transport:lan] response missing result
- [transport:manager] lan profile missing rpcUrl
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/cae4e3af1590aefd.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/services/transport/TransportManager.ts:174
const winner = await Promise.race([lanRace, tunnelRace]);
if (winner) {
// Close the losing transport.
void winner.loser.close().catch(() => {});
log('[transport:manager] race winner: %s', winner.transport.kind);
return winner.transport;
}
// Both failed in the race window — wait for whichever succeeds.
logErr('[transport:manager] race: both transports unhealthy; waiting…');
const result = await Promise.any([lanRace, tunnelRace]);
if (result) {
void result.loser.close().catch(() => {});
log('[transport:manager] fallback winner: %s', result.transport.kind);
return result.transport;
}
throw new Error('[transport:manager] all transports failed to connect');
}
}
// -- convenience factory ------------------------------------------------------
/**
* Build a TransportManager from a ConnectionProfile.
* `localRpcUrl` / `localToken` are only needed for kind="local".
*/
export function createTransportManager(
profile: ConnectionProfile,
opts: {
localRpcUrl?: () => Promise<string>;
localToken?: () => Promise<string | null>;
backendSocketUrl?: string;
} = {}
): TransportManager {
const noop = () => Promise.resolve(null);View on GitHub (pinned to 7491200858)