◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/API / SDK
◈ API / SDK/2026-05-22Advanced

Why Gemini API Returns Empty Responses with finishReason: RECITATION, and the Prompt + Post-Processing Design That Stopped It

Run a Gemini content agent long enough and one day logs fill with finishReason: 'RECITATION' and empty content arrays. This is the verbatim-quotation safety system firing. Here is the prompt rewriting pattern and TypeScript post-processor I deployed across six auto-publishing pipelines at Dolice — it dropped my incident rate by 90%.

gemini-api286recitation-blocksafety-settingsprompt-designproduction140

✦ Premium Article

Run a Gemini content agent in production for long enough and one day this lands in your logs: finishReason: "RECITATION", status 200 OK, and candidates[0].content.parts is empty. The call looks like a success on the wire, but nothing came back. As an indie developer at Dolice running six auto-publishing pipelines (Claude Lab, Gemini Lab, Antigravity Lab, Rork Lab, plus the older content sites Lacrima and Mystery), I went through a month where this blocked roughly 20 article generations and I kept waking up to short daily output counts.

Recitation block is the safety system that fires when Gemini judges its in-flight response is about to emit a long verbatim quote of copyrighted material. It is independent of safetySettings, so you cannot turn it off — it has to be addressed at both the prompt and the post-processing layer.

Here is the end-to-end design — detector, paraphrase-forced prompt, three-tier fallback, model switch — that I shipped to production, plus the failure rates I measured before and after.

Five conditions that trigger recitation block

Across six months of logs, the trigger patterns settled into five buckets:

  1. Requests that long-quote existing articles, news, or papers (≈45%): "based on the body of this article…", "summarize chapter 3 of this paper…" — anything that nudges the model to reproduce a stretch of the source verbatim
  2. Lyrics, poems, famous literary text (≈20%): even small fragments of copyrighted lyrics or fiction
  3. Long verbatim copies of public codebases (≈15%): asking the model to reproduce an entire framework tutorial as-is
  4. Headline + lead paragraph stacking in news summarizers (≈12%): asking the model to reproduce the headline, dek, and opening graf in sequence
  5. Verbatim re-emission of long structured data (≈8%): "echo back this dataset as JSON" patterns that try to mirror every field

Retry success rates were roughly 5% / 0% / 30% / 10% / 60%. Causes 1–4 are prompt-design problems, not transient errors. Without rewriting the prompt, retries do nothing.

Cleanly detecting the block on response

The API returns HTTP 200 with finishReason: "RECITATION" and an empty parts array. A naive implementation reads it as an empty success.

import { GoogleGenerativeAI } from "@google/generative-ai";
 
interface DetectionResult {
  isRecitation: boolean;
  partial: string;
  citationMetadata?: unknown;
}
 
function detectRecitation(response: any): DetectionResult {
  const candidate = response?.candidates?.[0];
  if (!candidate) return { isRecitation: false, partial: "" };
 
  const finishReason = candidate.finishReason ?? "";
  const isRecitation = finishReason === "RECITATION";
 
  // On streaming, partial may still contain tokens emitted before the block fired
  const partial = (candidate.content?.parts ?? [])
    .map((p: { text?: string }) => p.text ?? "")
    .join("");
 
  return {
    isRecitation,
    partial,
    citationMetadata: candidate.citationMetadata,
  };
}

citationMetadata sometimes contains hints about which public source the response was matching against. I log this so the offending prompt is easy to find and rewrite.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Recognize the five prompt patterns that trigger Gemini's recitation block, with the API response shape (finishReason + citationMetadata) you need to detect it cleanly
✦Adopt the 'paraphrase-forced prompt' template that took my own incident rate from ~20/month to 1–2/month — over 90% reduction — directly out of a production pipeline
✦Take home the three-tier fallback (retry / paraphrase prompt / chunked re-aggregation) and a model-switch backstop, with cost numbers from six months of production logs
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

◈ API / SDK2026-04-24
Designing Production-Grade Safety Controls for the Gemini API: A Layered Moderation Architecture That Minimizes False Positives Without Letting Abuse Through
Relying on the Gemini API's Safety Settings alone leads to legitimate questions getting false-blocked or carefully crafted malicious prompts slipping through. This guide shows a four-layer moderation design that stands up in production.
◈ API / SDK2026-07-15
Sample what you already accepted — an audit budget that catches silent quality drift
A confidence gate only ever looks at output the model hesitated on. Silent drift sinks into the batch that sailed through. Working from a fixed 30-minutes-a-day review budget, this walks through deriving detection time from the binomial, reallocating the same budget across risk strata, and catching slow decay with a cumulative monitor.
◈ API / SDK2026-07-04
When Gemini API Leaks Japanese Into Your English Output Once in a While — Field Notes on Measuring the Contamination Rate and Tightening It in Stages
You told Gemini to answer in English, and 3 out of 100 runs slip a Japanese sentence into the tail. Here is why you cannot stop that 'once in a while', and a production pattern that measures the contamination rate as an SLO and tightens it with graded recovery, with working code.