tinyhumansai/openhuman · error
[transport:manager] unknown profile kind
Error message
[transport:manager] unknown profile kind: ${kind} What it means
getTransport() fell through all four known kinds (local, cloud, lan, tunnel) and hit the exhaustive-default throw. ConnectionProfile.kind is the literal union 'local' | 'lan' | 'tunnel' | 'cloud', so at type level this is unreachable — it only happens at runtime with data that bypassed the types.
Solutions
- Reset the persisted coreMode/profile state so a default { kind: 'local' } profile is rebuilt
- Add a rehydrate guard/migration that maps unknown kinds to 'local' (Redux persist migrate or a transform)
- If adding a new kind, extend the ConnectionProfile union and this switch in the same change
Example fix
// before const kind = persisted.kind; // could be 'remote' from an old build // after const KNOWN = ['local', 'lan', 'tunnel', 'cloud'] as const; const kind = KNOWN.includes(persisted.kind) ? persisted.kind : 'local';
Defensive patterns
Strategy: type-guard
Type guard
const PROFILE_KINDS = ['local', 'lan', 'tunnel', 'cloud'] as const;
type ProfileKind = (typeof PROFILE_KINDS)[number];
function isProfileKind(v: unknown): v is ProfileKind {
return typeof v === 'string' && (PROFILE_KINDS as readonly string[]).includes(v);
} Try / catch
try { await manager.getTransport(); }
catch (err) {
if (err instanceof Error && err.message.includes('unknown profile kind')) {
dispatch(resetCoreMode()); // rebuild a clean { kind: 'local' } profile
} else throw err;
} Prevention
- Guard rehydrated state with isProfileKind before it reaches TransportManager
- When adding a profile kind, update union + switch + migrations in one commit
- Reset persisted profiles on app downgrade rather than trusting foreign shapes
When it happens
Trigger: A persisted profile from a different app version containing a since-removed or since-added kind string (e.g. an old 'remote' kind); corrupted localStorage/persisted Redux data; JSON injected from tests or devtools; a newer backend writing kinds this build does not know.
Common situations: Downgrading the app while keeping persisted state; two products sharing the storage key; hand-edited state during debugging.
Related errors
- [transport:manager] cloud profile missing rpcUrl
- [transport:manager] lan profile missing rpcUrl
- [transport:cloud] HTTP
- [transport:lan] HTTP
- [transport:manager] tunnel profile missing channelId or…
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/fade56031214fcf0.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/services/transport/TransportManager.ts:101
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.
*/
private async raceLanAndTunnel(): Promise<CoreTransport> {
const { rpcUrl, channelId, corePubkey, sessionToken, pairingToken, devicePrivkey } =
this.profile;
if (!channelId || !corePubkey) {
throw new Error('[transport:manager] tunnel profile missing channelId or corePubkey');
}
const tunnelToken = sessionToken ?? pairingToken;
if (!tunnelToken) {
throw new Error('[transport:manager] tunnel profile missing sessionToken or pairingToken');View on GitHub (pinned to 7491200858)