can1357/oh-my-pi · error · Error
Handoff generation produced no content
Error message
Handoff generation produced no content
What it means
generateDocument treats an empty generation as a hard failure when the handoff was user-initiated: if the LLM turn completes without producing content, it throws instead of silently returning. For autoTriggered handoffs it instead returns undefined so maintenance can fall back to the next compaction method — the throw exists to avoid a misleading 'cancelled' result on explicit requests.
Source
Thrown at packages/coding-agent/src/session/session-handoff.ts:206
const handoffText = this.#host.deobfuscateFromProvider(rawHandoffText);
throwIfHandoffAborted(handoffSignal);
if (!handoffText || handoffText.trim().length === 0) {
// Empty/whitespace-only generation is a real failure, not a user
// cancellation. #7904 stopped masking provider errors as "Handoff
// cancelled"; an empty document is the remaining path that produced the
// same misleading, undebuggable message (#7993).
logger.warn("Handoff generation produced no content", {
sessionId: this.#host.sessionId(),
autoTriggered: options?.autoTriggered ?? false,
});
// Auto-handoff is best-effort: returning undefined lets maintenance fall
// back to the next compaction method. A user-initiated handoff must
// surface the failure instead of a silent, misleading "cancelled".
if (options?.autoTriggered) {
return undefined;
}
throw new Error("Handoff generation produced no content");
}
let savedPath: string | undefined;
if (options?.autoTriggered && this.#host.settings.get("compaction.handoffSaveToDisk")) {
const artifactsDir = this.#host.sessionManager.getArtifactsDir();
if (artifactsDir) {
const handoffFilePath = path.join(artifactsDir, createHandoffFileName());
try {
await Bun.write(handoffFilePath, `${handoffText}\n`);
savedPath = handoffFilePath;
} catch (error) {
logger.warn("Failed to save handoff document to disk", {
path: handoffFilePath,
error: error instanceof Error ? error.message : String(error),
});
}
} else {
logger.debug("Skipping handoff document save because session is not persisted");View on GitHub (pinned to 9690622007)
Solutions
- Retry the handoff generation, possibly with a different model or higher output limit
- Check provider logs/response for blocked or empty completions and fix the request (prompt, maxTokens)
- Switch to a non-handoff compaction method (e.g. summarize) as the fallback
- Catch the error for user-initiated compaction and surface a retry option
Example fix
// before
await handoff.generateDocument(signal); // throws on empty output
// after
try {
await handoff.generateDocument(signal);
} catch (err) {
if (err.message === "Handoff generation produced no content") {
await session.compact(); // fallback method
return;
}
throw err;
} Defensive patterns
Strategy: fallback
Try / catch
try {
await handoff.generateDocument(signal);
} catch (err) {
if (err instanceof Error && err.message === "Handoff generation produced no content") {
await session.compact({ method: "summarize" }); // alternative compaction
return;
}
throw err;
} Prevention
- Set adequate max output tokens for the handoff generation
- Retry once with a different model on empty responses
- Prefer auto-triggered handoff (returns undefined) where fallback is acceptable
- Monitor provider-side blocks/filters that produce empty completions
When it happens
Trigger: generateDocument (options.autoTriggered falsy) where the handoff LLM response contains no usable content (empty stream, model returned nothing, response filtered).
Common situations: Provider returned an empty/blocked response; max-tokens set too low; upstream API error swallowed into an empty result; model produced only tool calls with no text.
Related errors
- Empty model response
- Handoff cancelled
- No model selected for handoff
- No API key for ${model.provider}
- GPT-5 Harmony leak persisted after ${harmonyRetryAttempt} re
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/7c466cfd26fa7ee8.
Report an issue: GitHub.