ruvnet/ruflo · error
Client heartbeat timeout
Error message
Client heartbeat timeout
What it means
The heartbeat interval found a client whose isAlive flag was still false after the last ping — it never sent a pong within heartbeatTimeout. The server logs the timeout and disconnects the dead client (standard WS liveness reaping), freeing its connection slot.
Source
Thrown at v3/mcp/transport/websocket.ts:478
if (this.config.enableBinaryMode) {
// Could implement binary protocol here
return JSON.stringify(message);
}
return JSON.stringify(message);
}
/**
* Start heartbeat interval
*/
private startHeartbeat(): void {
const interval = this.config.heartbeatInterval || 30000; // 30 seconds
const timeout = this.config.heartbeatTimeout || 10000; // 10 seconds
this.heartbeatTimer = setInterval(() => {
for (const client of this.clients.values()) {
if (!client.isAlive) {
// Client didn't respond to last ping
this.logger.warn('Client heartbeat timeout', { id: client.id });
client.ws.terminate();
this.clients.delete(client.id);
continue;
}
client.isAlive = false;
try {
client.ws.ping();
} catch {
// Ignore ping errors
}
}
}, interval);
}
/**
* Stop heartbeat interval
*/View on GitHub (pinned to fa13ee4ad6)
Solutions
- Verify the client sends heartbeat/ping frames within the configured interval.
- Increase the heartbeat timeout for high-latency clients.
- Check for client-side event-loop stalls delaying heartbeats, and ensure reconnect logic recovers the socket.
Defensive patterns
Strategy: retry
When it happens
Trigger: WebSocket client fails to respond to heartbeat pings within the timeout; dead peer, suspended browser tab, or broken network path; server closes and cleans up the connection.
Common situations: See trigger scenarios.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/cd1443a6fd684e19.
Report an issue: GitHub.