tinyhumansai/openhuman · error
Socket not connected — no client ID for event routing
Error message
Socket not connected — no client ID for event routing
What it means
Thrown by chatSend() before sending: the chat turn is dispatched via 'openhuman.channel_web_chat' and the core streams the turn's events (tool_call, chat_done, chat_error) back over the socket keyed by client_id = socket.id. If socketService.getSocket() returns no socket or the socket has no id, the turn would be launched blind with no event lane, so the client refuses to send.
Source
Thrown at app/src/services/chatService.ts:1268
queueMode?: QueueMode | null;
}
/**
* Send a chat message via core RPC.
*
* The Rust core spawns the agent loop asynchronously and streams events
* (tool_call, tool_result, chat_done, chat_error) back over the socket
* connection using the `client_id` (socket ID) for routing.
*
* Returns the turn's `request_id` (from the RPC ack) when the core provides
* one — used by `parallel` sends to register the forked turn's stream lane.
* `undefined` if the ack carried no id.
*/
export async function chatSend(params: ChatSendParams): Promise<string | undefined> {
const socket = socketService.getSocket();
const clientId = socket?.id;
if (!clientId) {
throw new Error('Socket not connected — no client ID for event routing');
}
const result = await callCoreRpc({
method: 'openhuman.channel_web_chat',
params: {
client_id: clientId,
thread_id: params.threadId,
message: params.message,
model_override: params.model ?? undefined,
profile_id: params.profileId ?? undefined,
locale: params.locale ?? undefined,
speak_reply: params.speakReply ?? undefined,
source: params.source ?? undefined,
session_id: params.sessionId ?? undefined,
queue_mode: params.queueMode ?? undefined,
},
});
View on GitHub (pinned to a221052e0d)
Solutions
- Gate the send action on socket connectivity (the Redux socket slice / socketService state) and disable/queue the composer while disconnected
- Trigger or await socket reconnect before retrying the send — the message text should be preserved in the composer
- If it persists, restart the core and let the app reconnect (Settings -> Restart Core drives the full reconnect path)
- In tests, mock socketService.getSocket to return { id: 'test-socket' }
Example fix
// before
const requestId = await chatSend({ threadId, message });
// after
const socket = socketService.getSocket();
if (!socket?.id) {
setPendingMessage(message); // queue until reconnect
await socketService.reconnect();
}
const requestId = await chatSend({ threadId, message }); Defensive patterns
Strategy: validation
Validate before calling
const socket = socketService.getSocket();
if (!socket?.id) {
setQueuedMessage(params); // preserve the draft
await ensureSocketConnected(); // reconnect before dispatching the turn
}
await chatSend(params); Type guard
function hasSocketId(s: unknown): s is { id: string } {
return !!s && typeof s === 'object' && typeof (s as { id?: unknown }).id === 'string' && (s as { id: string }).id.length > 0;
} Try / catch
try {
return await chatSend(params);
} catch (e) {
if (e instanceof Error && e.message.includes('no client ID')) {
await socketService.reconnect();
return chatSend(params); // message preserved by the caller
}
throw e;
} Prevention
- Disable or queue the composer while the socket is disconnected (subscribe to the socket slice)
- Reconnect proactively after core restarts and resume/sleep events
- Never fire event-routed RPCs without a live socket id — by design they would stream nowhere
When it happens
Trigger: User hits send while the socket is disconnected: core was restarted, network dropped, auth expired and the socket closed, or the app is in a state where the socket service never connected. Also fires in tests that call chatSend without mocking a connected socket.
Common situations: Socket reconnect lag after core restart (user types faster than reconnect); laptop sleep/resume; backend/auth expiry closing the socket; UI send button not gated on connectivity state.
Related errors
- [transport:manager] all transports failed to connect
- core not reachable at ${RPC_URL} — start it with `cargo run
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/913406329ba9c400.
Report an issue: GitHub.