decolua/9router · warning
FUSION Panel ${model} returned empty content
Error message
FUSION Panel ${model} returned empty content What it means
After a panel model returns a 2xx response, the FUSION service parses its JSON and extracts text via extractPanelText. If the payload parses but contains no usable content (empty choices/message content, whitespace-only text), the panel is skipped with this warning and excluded from fusion.
Source
Thrown at open-sse/services/combo.js:601
log.info("FUSION", `fan-out collected in ${Date.now() - t0}ms`);
// 2. Collect successful answers.
const answers = [];
for (let i = 0; i < settled.length; i++) {
const res = settled[i];
const model = panel[i];
if (!res) { log.warn("FUSION", `Panel ${model} dropped (straggler/timeout)`); continue; }
if (res.__timeout) { log.warn("FUSION", `Panel ${model} timed out`); continue; }
if (res.__error) { log.warn("FUSION", `Panel ${model} threw`, { error: res.__error?.message || String(res.__error) }); continue; }
if (!res.ok) { log.warn("FUSION", `Panel ${model} failed`, { status: res.status }); continue; }
try {
const json = await res.clone().json();
const text = extractPanelText(json);
if (text) {
answers.push({ model, text });
log.info("FUSION", `Panel ${model} ok (${text.length} chars)`);
} else {
log.warn("FUSION", `Panel ${model} returned empty content`);
}
} catch (e) {
log.warn("FUSION", `Panel ${model} unparseable`, { error: e.message || String(e) });
}
}
// 3. Degrade gracefully when the panel is too thin to fuse.
if (answers.length === 0) {
log.warn("FUSION", "All panel models failed");
return new Response(
JSON.stringify({ error: { message: "All fusion panel models failed" } }),
{ status: 503, headers: { "Content-Type": "application/json" } }
);
}
if (answers.length === 1) {
log.info("FUSION", `Only ${answers[0].model} succeeded — answering directly (no fusion)`);
return handleSingleModel(body, answers[0].model);
}View on GitHub (pinned to 90b52e06ff)
Solutions
- Inspect the panel's raw response (enable debug logging) to see where the content actually sits
- Raise max_tokens for the request so the model can produce non-empty output
- Confirm the model returns standard OpenAI-style choices[0].message.content, or add a direct translator for that provider
- Retry the prompt — one-off empty content (safety filter) usually resolves with rephrasing
- Check whether a content filter on the provider account is suppressing output
Example fix
// before
defaults: { max_tokens: 1 }
// after
defaults: { max_tokens: 4096 } Defensive patterns
Strategy: validation
Validate before calling
const json = await res.clone().json();
const text = extractPanelText(json);
if (typeof text !== 'string' || !text.trim()) throw new Error(`panel ${model} returned empty content`); Type guard
const hasContent = (json) => typeof json?.choices?.[0]?.message?.content === 'string' && json.choices[0].message.content.trim().length > 0;
Try / catch
try {
const text = extractPanelText(await res.clone().json());
if (!text) throw new Error('empty content');
return text;
} catch (e) {
console.warn(`panel unusable: ${e.message}`); // excluded from fusion, request still served
return null;
} Prevention
- Set a sane max_tokens floor so completions are never truncated to empty
- Rephrase prompts that trip provider safety filters
- Use direct translators for nonstandard providers so content lands where extractPanelText reads
- Log the raw JSON when extraction fails to catch provider shape drift early
When it happens
Trigger: Upstream returned 200 with an empty body content — e.g. the model returned only a refusal stripped of content, a filter removed the output, max_tokens was set so low the completion is empty, or a provider returns a nonstandard success shape extractPanelText doesn't recognize.
Common situations: max_tokens=1 or tiny budget yields empty text; safety filters blank the content; a translator maps the provider's response into a shape where content lands in a field extractPanelText doesn't read (nonstandard model); streaming-only endpoints return an empty non-stream body.
Related errors
- Upstream returned empty audio
- Bing TTS returned empty audio
- ElevenLabs TTS returned empty audio
- Gemini TTS returned no audio (finishReason: ${reason}, voice
- Google TTS returned empty audio
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/2c2daa3735cdca07.
Report an issue: GitHub.