google-gemini/gemini-cli · error · InvalidStreamError
NO_RESPONSE_TEXT
NO_RESPONSE_TEXT
Error message
Model stream ended with empty response text.
What it means
The stream ended with a benign finishReason (typically STOP) but produced zero visible output text: no tool call was made, and after geminiChat.ts:1488-1497 strips zero-width/invisible characters and HTML comment blocks the remaining text is empty, with no reasoning thoughts (a thoughts-only response would have thrown THINKING_ONLY_RESPONSE first) and no blocked-finishReason variant (MAX_TOKENS/SAFETY/RECITATION/OTHER each have their own error). Tool-response turns (isOriginalFunctionResponse=true) are exempt, so this only fires on genuine user turns. Like all InvalidStreamErrors it is retried internally with a nudge before being surfaced.
Source
Thrown at packages/core/src/core/geminiChat.ts:1626
throw new InvalidStreamError(
'Model stream ended due to recitation settings (RECITATION) with empty response text.',
'RECITATION_BLOCKED',
);
}
if (finishReason === FinishReason.OTHER) {
throw new InvalidStreamError(
'Model stream ended due to other settings (OTHER) with empty response text.',
'OTHER_BLOCKED',
);
}
if (hasThoughts) {
throw new InvalidStreamError(
'Model stream ended with empty response text but contained reasoning thoughts.',
'THINKING_ONLY_RESPONSE',
);
}
if (!isOriginalFunctionResponse) {
throw new InvalidStreamError(
'Model stream ended with empty response text.',
'NO_RESPONSE_TEXT',
);
}
}
}
// Flush buffered thoughts from the successful attempt
for (const thought of bufferedThoughts) {
this.chatRecordingService.recordThought(thought);
}
// Flush buffered usage metadata and token counts from the successful attempt
if (bufferedUsageMetadata) {
this.chatRecordingService.recordMessageTokens(bufferedUsageMetadata);
if (bufferedUsageMetadata.promptTokenCount !== undefined) {
this.lastPromptTokenCount = bufferedUsageMetadata.promptTokenCount;
}View on GitHub (pinned to 3c311beac2)
Solutions
- Retry the turn with backoff — most occurrences are one-off model flakiness; the library already retried 3 times with a nudge, so a single outer retry after a pause usually clears it.
- Loosen output-format instructions in the prompt: forbid empty replies ('always include at least one sentence of content'), and do not ask the model to wrap its entire answer in HTML comments or emit format-only scaffolding.
- If it reproduces on one prompt, minimize that prompt and test directly against the Gemini API to confirm the model itself returns empty content; then restructure the prompt or switch model version.
- Check generationConfig (adequate maxOutputTokens, sensible temperature) and, if you suspect quiet refusals, review safetySettings for the request.
Example fix
// before: format-only instructions that can yield an empty visible reply
const system = 'Respond ONLY with an HTML comment containing the plan. No other text.';
// after: same machine-readable goal, empty output forbidden
const system = 'Write the plan inside an HTML comment. Before the comment, write one short sentence summarizing the plan. Never send an empty reply.';
// plus an outer safety net:
async function turnWithNudge(chat, msg) {
try {
return await collect(chat.sendMessageStream(msg));
} catch (e) {
if (e instanceof InvalidStreamError && e.type === 'NO_RESPONSE_TEXT') {
return collect(chat.sendMessageStream('Your last reply was empty. Please answer again with actual content.'));
}
throw e;
}
} Defensive patterns
Strategy: retry
Type guard
import { InvalidStreamError } from './packages/core/src/core/geminiChat.js';
function isNoResponseTextError(e: unknown): e is InvalidStreamError & { type: 'NO_RESPONSE_TEXT' } {
return e instanceof InvalidStreamError && e.type === 'NO_RESPONSE_TEXT';
} Try / catch
try {
for await (const chunk of chat.sendMessageStream(userMsg)) { handle(chunk); }
} catch (e) {
if (isNoResponseTextError(e)) {
// Library already retried with a nudge; resend the turn once with an explicit anti-empty instruction.
return runTurn(chat, userMsg, { extraInstruction: 'Never reply with empty or comment-only content.' });
}
throw e;
} Prevention
- Add an explicit 'never send an empty reply' rule to the system prompt, especially when the prompt restricts output to XML/HTML-comment formats.
- Avoid instructing the model to emit ONLY zero-width/invisible scaffolding or comment blocks — the stream validator strips both and treats the result as empty (geminiChat.ts:1488-1497).
- Track the NO_RESPONSE_TEXT rate per prompt/model; a prompt-specific cluster means the prompt shape is the cause, not bad luck.
- Keep maxOutputTokens generous and temperature non-degenerate so the model does not collapse to repeated empty completions.
When it happens
Trigger: A sendMessageStream turn whose consolidated parts contain only whitespace, zero-width characters, or HTML comment blocks (all stripped at geminiChat.ts:1488-1497), or no text parts at all, while the model still reports finishReason STOP. Commonly caused by prompts that force a narrow output format (e.g., 'reply only inside <!-- ... --> comments', 'output XML only, no prose'), models that intermittently emit a bare STOP with empty candidates, or gateways that forward an empty final chunk.
Common situations: System prompts demanding machine-only formats (XML-only, comment-wrapped) that push the model to emit format scaffolding with no payload; temperature=0 loops that repeat the same empty completion; silent refusals on borderline prompts that return STOP instead of SAFETY; a mock/proxy test harness that yields a chunk with finishReason STOP but empty parts; observed intermittently under heavy load — most occurrences are transient model flakiness.
Related errors
- NO_FINISH_REASON
- MALFORMED_FUNCTION_CALL
- [A2AClientManager] sendMessageStream Error [${agentName}]: $
- [A2AClientManager] sendMessageStream Error [${agentName}]: U
- Failed to create chat object: ${getErrorMessage(e)}
AI-assisted analysis of google-gemini/gemini-cli@3c311beac2 (2026-08-21).
Data as JSON: /api/errors/1c6ac0312980aad8.
Report an issue: GitHub.