tinyhumansai/openhuman · error

[transport:manager] lan profile missing rpcUrl

Error message

[transport:manager] lan profile missing rpcUrl

What it means

Same manager guard for kind === 'lan': the profile claims LAN mode but carries no rpcUrl, so there is nothing to point LanHttpTransport at. The lan branch destructures only rpcUrl (LAN has no auth token in this transport).

Solutions

  1. Re-add the LAN host in Settings → Core connection so rpcUrl (http://<host>:<port>/rpc) is captured
  2. Validate the profile shape before createTransportManager and discard incomplete ones (fall back to kind 'local')
  3. If persisting programmatically, never write kind:'lan' without rpcUrl — write it in one atomic update

Example fix

// before
const profile = { kind: 'lan' };
// after
const profile = { kind: 'lan', rpcUrl: 'http://192.168.1.20:5800/rpc' };
Defensive patterns

Strategy: validation

Validate before calling

function assertLanProfileReady(p: ConnectionProfile): void {
  if (p.kind === 'lan' && !p.rpcUrl) {
    throw new Error('lan profile incomplete — capture the host rpcUrl before connecting');
  }
}

Type guard

function isCompleteLanProfile(p: ConnectionProfile): boolean {
  return p.kind !== 'lan' || (typeof p.rpcUrl === 'string' && p.rpcUrl.length > 0);
}

Prevention

When it happens

Trigger: A LAN profile saved before the host's address was captured (pairing flow interrupted); persisted state migration dropping the field; manual construction with kind 'lan' but empty rpcUrl.

Common situations: User added the LAN host, left settings mid-flow, and the half-built profile persisted; the host's IP changed and a cleanup path nulled rpcUrl; fixtures/tests omitting the URL.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/308f72eeecc40108. Report an issue: GitHub.

Appendix: source

Thrown at app/src/services/transport/TransportManager.ts:90

      const t = new LocalTransport(this.localRpcUrl, this.localToken);
      log('[transport:manager] → LocalTransport');
      return t;
    }

    if (kind === 'cloud') {
      const { rpcUrl, sessionToken } = this.profile;
      if (!rpcUrl) {
        throw new Error('[transport:manager] cloud profile missing rpcUrl');
      }
      const t = new CloudHttpTransport(rpcUrl, sessionToken ?? null);
      log('[transport:manager] → CloudHttpTransport rpcUrl=%s', rpcUrl);
      return t;
    }

    if (kind === 'lan') {
      const { rpcUrl } = this.profile;
      if (!rpcUrl) {
        throw new Error('[transport:manager] lan profile missing rpcUrl');
      }
      const t = new LanHttpTransport(rpcUrl);
      log('[transport:manager] → LanHttpTransport rpcUrl=%s', rpcUrl);
      return t;
    }

    if (kind === 'tunnel') {
      return this.raceLanAndTunnel();
    }

    throw new Error(`[transport:manager] unknown profile kind: ${kind}`);
  }

  /**
   * Race LAN (with 2 s timeout) against Tunnel.
   * Whichever responds to `openhuman.ping` first wins.
   * If LAN wins but later fails, caller should call reset() to re-race.
   */

View on GitHub (pinned to 7491200858)