can1357/oh-my-pi · error · AIError.ProviderResponseError

Google API stream ended without a finish reason (connection

Error message

Google API stream ended without a finish reason (connection dropped or response truncated)

What it means

consumeGoogleStream reached end-of-stream without ever seeing a candidate finishReason, meaning the SSE stream from Google terminated abnormally. The library throws AIError.ProviderResponseError with kind "incomplete-stream" because a complete Google response always ends with a finish reason.

Source

Thrown at packages/ai/src/providers/google-shared.ts:767

					input: 0,
					output: 0,
					cacheRead: 0,
					cacheWrite: 0,
					total: 0,
				},
			};
			calculateCost(model, output.usage);
		}
	}

	flushCurrent();

	if (options?.signal?.aborted) {
		throw new AIError.AbortError();
	}

	if (!sawFinishReason) {
		throw new AIError.ProviderResponseError(
			"Google API stream ended without a finish reason (connection dropped or response truncated)",
			{ provider: model.provider, kind: "incomplete-stream" },
		);
	}

	if (output.stopReason === "aborted" || output.stopReason === "error") {
		throw new AIError.ProviderResponseError(output.errorMessage ?? "An unknown error occurred", {
			provider: model.provider,
			kind: "output",
		});
	}
}

/**
 * Generation/sampling fields that map directly onto Gemini's `GenerateContentConfig`.
 * Excludes any provider-specific extensions (`topP`/`topK`/etc are all forwarded as-is).
 */
interface GoogleGenerationConfig extends GenerateContentConfig {

View on GitHub (pinned to 9690622007)

Solutions

  1. Implement retry with exponential backoff — these are usually transient network failures
  2. Catch AIError.ProviderResponseError with kind "incomplete-stream" and re-issue the request, keeping any partial output if acceptable
  3. Check network path: disable VPN/proxy or raise its stream timeout
  4. Reduce max output tokens so responses complete within connection lifetime

Example fix

// before
const result = await streamGoogle(model, params);
// after
async function withRetry() {
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      return await streamGoogle(model, params);
    } catch (err) {
      if (err instanceof AIError.ProviderResponseError && err.context?.kind === "incomplete-stream" && attempt < 2) {
        await Bun.sleep(2 ** attempt * 500);
        continue;
      }
      throw err;
    }
  }
}
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try {
  return await streamGoogle(model, params, { signal });
} catch (err) {
  if (err instanceof AIError.ProviderResponseError && err.context?.kind === "incomplete-stream" && !signal.aborted) {
    return await withBackoff(() => streamGoogle(model, params, { signal }), 3);
  }
  throw err;
}

Prevention

When it happens

Trigger: The HTTP connection to Google dropped mid-stream; a proxy/load-balancer cut the SSE connection; server-side crash mid-generation; network interruption; response truncated by infrastructure timeout.

Common situations: Long generations over flaky networks; corporate proxies with idle/stream timeouts; Cloud Run / API gateway response limits; transient Google infrastructure errors.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f7cc0dd7a94cbfd1. Report an issue: GitHub.