chatboxai/chatbox · error · MidStreamApiError
${parsed.error.message || 'Upstream Google Generative AI str
Error message
${parsed.error.message || 'Upstream Google Generative AI stream error'} What it means
Thrown by the Gemini stream-error parser when an SSE event from Google Generative AI carries a structured `error` object AND no content has been forwarded to the user yet: it raises a regular ApiError (not MidStreamApiError) using the upstream error.message (or a default) and error.code as statusCode (default 503). The branch is selected by forwardedContent being falsy.
Source
Thrown at src/shared/models/utils/gemini-stream-error.ts:69
if (!data || data === '[DONE]') {
return
}
let parsed: { error?: { message?: unknown; code?: unknown } }
try {
parsed = JSON.parse(data) as { error?: { message?: unknown; code?: unknown } }
} catch {
return
}
if (!parsed?.error || typeof parsed.error !== 'object') {
return
}
const message =
typeof parsed.error.message === 'string' && parsed.error.message
? parsed.error.message
: 'Upstream Google Generative AI stream error'
const statusCode = typeof parsed.error.code === 'number' ? parsed.error.code : 503
if (forwardedContent) {
throw new MidStreamApiError(message, data, statusCode)
}
throw new ApiError(message, data, statusCode)
}
// Returns true when the event carried `data:` payload (actual stream content,
// as opposed to SSE comments/keepalives).
const processEvent = (event: string): boolean => {
const dataLines = event
.split(/\r?\n/)
.filter((line) => line.startsWith('data:'))
.map((line) => line.slice('data:'.length).trimStart())
// No SSE framing: some proxies report application/json and send a plain
// JSON body, so check the raw payload for the same error shape.
const payload = dataLines.length > 0 ? dataLines.join('\n') : event.trim()
if (payload) {
throwIfGoogleErrorData(payload)
}
return dataLines.length > 0View on GitHub (pinned to 81571269ad)
Solutions
- Read ApiError.statusCode: 400 → fix prompt/parameters; 401/403 → rotate the Gemini API key; 429 → quota, back off and retry; 404 → wrong model id.
- Inspect ApiError.responseBody for Google's structured error (status, details) which often names the exact rejected field or policy.
- Pre-validate the prompt against Gemini's content policy and token limits before streaming to avoid safety-filter errors.
- Confirm the model id in provider config is a currently available Gemini model id.
Example fix
// before
if (forwardedContent) {
throw new MidStreamApiError(message, data, statusCode)
}
throw new ApiError(message, data, statusCode)
// after — keep the structured error body for diagnostics
if (forwardedContent) {
throw new MidStreamApiError(message, JSON.stringify(parsed.error), statusCode)
}
throw new ApiError(message, JSON.stringify(parsed.error), statusCode) Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate Gemini request preconditions to avoid early-stream errors.
function geminiRequestLikelyValid(modelId: string, apiKey: string, promptChars: number): string | null {
if (!apiKey) return 'Missing Gemini API key'
if (!modelId.startsWith('gemini-')) return `Unknown model id: ${modelId}`
if (promptChars > 1_000_000) return 'Prompt exceeds context limit'
return null
} Type guard
function isGeminiStreamApiError(e: unknown): e is ApiError {
return e instanceof ApiError && typeof (e as any).statusCode === 'number'
} Try / catch
try {
return await sdk.chatStream(messages, opts)
} catch (e) {
if (e instanceof ApiError && typeof e.statusCode === 'number') {
if (e.statusCode === 401 || e.statusCode === 403) rotateGeminiKey()
else if (e.statusCode === 429) return retryWithBackoff(() => sdk.chatStream(messages, opts))
else showUser(`Gemini: ${e.message}`)
return
}
throw e
} Prevention
- Use a current Gemini model id — deprecated ids return 404 as the first frame.
- Keep prompts within content policy; run a safety pre-check for high-risk content.
- Set sane quotas/billing alerts so 429s are rare.
When it happens
Trigger: Gemini streaming endpoint emits an error event before any data: content frame — e.g. prompt safety filter, invalid API key, quota exhausted, malformed request, model not found. The JSON parses, has a non-null object error, and forwardedContent is false, so ApiError (not MidStreamApiError) is thrown.
Common situations: Invalid Gemini API key (401/403); request tripped a safety filter; quota/billing limit hit; requested model name is unavailable; region restriction; prompt exceeds token limit; all of these arriving as the first SSE frame before any content.
Related errors
- No readable text content found in EPUB file
- knowledge_base_parsed_content_too_large
- Embedding batch failed: expected ${batchTexts.length}, got $
- Failed to search knowledge base (id: ${kbId}). Please try ag
- No response body
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/9f8f9b8d3a5fc22b.
Report an issue: GitHub.