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

  1. Inspect the panel's raw response (enable debug logging) to see where the content actually sits
  2. Raise max_tokens for the request so the model can produce non-empty output
  3. Confirm the model returns standard OpenAI-style choices[0].message.content, or add a direct translator for that provider
  4. Retry the prompt — one-off empty content (safety filter) usually resolves with rephrasing
  5. 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

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


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/2c2daa3735cdca07. Report an issue: GitHub.