{"record":{"id":"976817869bfdf5cb","repo":"can1357/oh-my-pi","slug":"request-blocked-by-google-chunk-promptfeedback","errorCode":null,"errorMessage":"Request blocked by Google (${chunk.promptFeedback.blockReason})${detail ? `: ${detail}` : \"\"}","messagePattern":"Request blocked by Google \\((.+?)\\)(.+?)` : \"\"\\}","errorType":"exception","errorClass":"AIError.ProviderResponseError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/google-shared.ts","lineNumber":626,"sourceCode":"\t\t\t\tcurrentBlock.thinking += tail;\n\t\t\t\tstream.push({ type: \"thinking_delta\", contentIndex: blockIndex(), delta: tail, partial: output });\n\t\t\t}\n\t\t}\n\t\tthinkingStripper = null;\n\t\tpushBlockEndEvent(currentBlock, blockIndex(), output, stream);\n\t};\n\n\tfor await (const chunk of googleStream) {\n\t\tif (chunk.error) {\n\t\t\tconst detail = chunk.error.message || chunk.error.status || \"unknown error\";\n\t\t\tconst message = `Google API stream error: ${detail}`;\n\t\t\tthrow typeof chunk.error.code === \"number\" && chunk.error.code >= 400\n\t\t\t\t? new AIError.GoogleApiError(message, chunk.error.code)\n\t\t\t\t: new AIError.ProviderResponseError(message, { provider: model.provider, kind: \"output\" });\n\t\t}\n\t\tif (!chunk.candidates?.length && chunk.promptFeedback?.blockReason) {\n\t\t\tconst detail = chunk.promptFeedback.blockReasonMessage;\n\t\t\tthrow new AIError.ProviderResponseError(\n\t\t\t\t`Request blocked by Google (${chunk.promptFeedback.blockReason})${detail ? `: ${detail}` : \"\"}`,\n\t\t\t\t{ provider: model.provider, kind: \"content-blocked\" },\n\t\t\t);\n\t\t}\n\t\tconst candidate = chunk.candidates?.[0];\n\t\tif (candidate?.content?.parts) {\n\t\t\tfor (const part of candidate.content.parts) {\n\t\t\t\tif (part.text !== undefined && part.text !== \"\") {\n\t\t\t\t\tif (!firstTokenSeen) {\n\t\t\t\t\t\tfirstTokenSeen = true;\n\t\t\t\t\t\tonFirstToken?.();\n\t\t\t\t\t}\n\t\t\t\t\tconst isThinking = isThinkingPart(part);\n\t\t\t\t\tif (\n\t\t\t\t\t\t!currentBlock ||\n\t\t\t\t\t\t(isThinking && currentBlock.type !== \"thinking\") ||\n\t\t\t\t\t\t(!isThinking && currentBlock.type !== \"text\")\n\t\t\t\t\t) {","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/google-shared.ts#L608-L644","documentation":"consumeGoogleStream received a chunk with no candidates but a promptFeedback.blockReason, meaning Google refused the request outright (prompt filtered before generation). The library throws AIError.ProviderResponseError with kind \"content-blocked\" and includes the block reason (e.g. SAFETY, RECITATION, BLOCKLIST, PROHIBITED_CONTENT) plus any blockReasonMessage detail.","triggerScenarios":"Streaming a generateContent request where Google's safety systems block the prompt: chunk.candidates is empty and chunk.promptFeedback.blockReason is set (typically SAFETY or BLOCKLIST).","commonSituations":"Prompts containing flagged content (violence, personal info, copyrighted text); over-aggressive safety thresholds; non-English prompts misclassified; changes in Google's safety filters over time.","solutions":["Inspect blockReason/blockReasonMessage in the thrown error's context and revise the prompt content","Lower safety thresholds via safetySettings on the request where policy allows","Catch AIError.ProviderResponseError and branch on kind === \"content-blocked\" to show a user-facing block message","Test the same prompt against the Google AI Studio playground to confirm filtering behavior"],"exampleFix":"// before\nconst result = await streamGoogle(model, params); // throws on block\n// after\ntry {\n  const result = await streamGoogle(model, params);\n} catch (err) {\n  if (err instanceof AIError.ProviderResponseError && err.context?.kind === \"content-blocked\") {\n    return { blocked: true, reason: err.message };\n  }\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"// client-side pre-screen cannot replicate Google's filters, but you can branch on the thrown kind:\nfunction isContentBlocked(err: unknown) {\n  return err instanceof AIError.ProviderResponseError && (err.context as any)?.kind === \"content-blocked\";\n}","typeGuard":"function isBlockFeedback(chunk: GoogleStreamChunk): boolean {\n  return !chunk.candidates?.length && Boolean(chunk.promptFeedback?.blockReason);\n}","tryCatchPattern":"try {\n  const stream = await streamGoogle(model, params);\n} catch (err) {\n  if (isContentBlocked(err)) {\n    return { blocked: true, detail: err.message }; // show user why their prompt was refused\n  }\n  throw err;\n}","preventionTips":["Set explicit safetySettings thresholds appropriate for your use case","Pre-screen or sanitize user prompts before sending to Google","Always catch and surface kind \"content-blocked\" distinctly from network errors","Test prompts across content categories to know your exposure to safety filters"],"tags":["google","safety-filter","content-blocking","streaming"],"backgroundTag":"content-blocked-by-provider","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}