From 12cfa0da03f45bbde1acd81dc49f02d9ee7ce9e6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:27:37 +0000 Subject: [PATCH] fix(react-hooks): prevent onComplete from firing prematurely when stream disconnects The onComplete callback in useRealtimeRun and useRealtimeRunWithStreams was firing whenever the SSE stream ended, regardless of whether the run had actually completed. This caused issues in self-hosted environments where reverse proxies (like Traefik) may close idle connections. The fix changes the condition from checking `run` to checking `run?.finishedAt`, ensuring onComplete only fires when the run has actually reached a terminal state. Fixes #2856 Co-authored-by: nicktrn --- packages/react-hooks/src/hooks/useRealtime.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react-hooks/src/hooks/useRealtime.ts b/packages/react-hooks/src/hooks/useRealtime.ts index c14a228f62..6aabac358a 100644 --- a/packages/react-hooks/src/hooks/useRealtime.ts +++ b/packages/react-hooks/src/hooks/useRealtime.ts @@ -149,8 +149,10 @@ export function useRealtimeRun( const hasCalledOnCompleteRef = useRef(false); // Effect to handle onComplete callback + // Only call onComplete when the run has actually finished (has finishedAt), + // not just when the subscription stream ends (which can happen due to network issues) useEffect(() => { - if (isComplete && run && options?.onComplete && !hasCalledOnCompleteRef.current) { + if (isComplete && run?.finishedAt && options?.onComplete && !hasCalledOnCompleteRef.current) { options.onComplete(run, error); hasCalledOnCompleteRef.current = true; } @@ -313,8 +315,10 @@ export function useRealtimeRunWithStreams< const hasCalledOnCompleteRef = useRef(false); // Effect to handle onComplete callback + // Only call onComplete when the run has actually finished (has finishedAt), + // not just when the subscription stream ends (which can happen due to network issues) useEffect(() => { - if (isComplete && run && options?.onComplete && !hasCalledOnCompleteRef.current) { + if (isComplete && run?.finishedAt && options?.onComplete && !hasCalledOnCompleteRef.current) { options.onComplete(run, error); hasCalledOnCompleteRef.current = true; }