Skip to content

reconnectToStream sends RESUME_REQUEST before WebSocket is open #1000

@alexanderjacobsen

Description

@alexanderjacobsen

Problem

WebSocketChatTransport.reconnectToStream() sends CF_AGENT_STREAM_RESUME_REQUEST after a fixed 100ms setTimeout, but after a page refresh the WebSocket hasn't opened yet at that point. The agent.send() throws, the try/catch swallows it, and after the 3s timeout the method returns nullstatus stays "ready".

Result: After refreshing during an active stream, the text eventually appears (via onAgentMessage), but useChat status never transitions to "streaming" — no abort button, no loading indicator.

Where

WebSocketChatTransport.reconnectToStream() in packages/ai-chat/src/react.ts:

const requestDelay = setTimeout(() => {
  if (!resolved) try {
    agent.send(JSON.stringify({ type: MessageType.CF_AGENT_STREAM_RESUME_REQUEST }));
  } catch {}
}, 100);

The 100ms delay was added to avoid a race with the server's automatic CF_AGENT_STREAM_RESUMING in onConnect, but it doesn't account for WebSocket connection time — which is almost always longer than 100ms on a fresh page load.

Suggested fix

Wait for the WebSocket to be open before sending:

function sendWhenOpen(agent, message) {
  if (agent.readyState === WebSocket.OPEN) {
    agent.send(message);
  } else {
    agent.addEventListener("open", () => agent.send(message), { once: true });
  }
}

Related

Follow-up to the fix in PR #999 (which fixed the ReadableStream return from reconnectToStream). The transport pipeline works correctly once the request actually reaches the server — the only issue is the send timing.

See also #896 (comment): #896 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions