decolua/9router · warning

FUSION Panel ${model} timed out

Error message

FUSION Panel ${model} timed out

What it means

In the FUSION (judge) flow of combo.js, each panel model's request is raced with a timeout; a panel entry marked `__timeout` (or missing, a straggler) is dropped from the answer pool and 'Panel <model> timed out' is logged. Fusion continues with the remaining panel answers — the request itself does not fail unless no panel answers survive. The message reflects a per-model time limit, not a hard error.

Source

Thrown at open-sse/services/combo.js:591

  // Flatten tool turns to prose so panel models keep context without emitting tool_calls.
  if (Array.isArray(panelBody.messages)) {
    panelBody.messages = flattenToolHistory(panelBody.messages);
  } else if (Array.isArray(panelBody.input)) {
    panelBody.input = flattenToolHistory(panelBody.input);
  }

  const t0 = Date.now();
  const calls = panel.map((m) => withTimeout(handleSingleModel(panelBody, m, true), cfg.panelHardTimeoutMs));
  const settled = await collectPanel(calls, { ...cfg, minPanel });
  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) {

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Replace or remove the slow model from the fusion panel — fusion tolerates fewer answers.
  2. Increase the fusion panel timeout in open-sse/config/runtimeConfig.js if your slowest member is legitimately slow.
  3. Check the provider's latency/health independently; a consistently timing-out member adds nothing.
  4. Reduce prompt size so panel members complete within the window.
  5. Ensure the slow provider isn't routed through a broken proxy (proxyFetch) or retrying internally.

Example fix

// before
{ name: 'fusion', models: ['openai/gpt-4o', 'ollama/70b-cpu'] } // ollama always times out
// after
{ name: 'fusion', models: ['openai/gpt-4o', 'anthropic/claude-sonnet'] }
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: A panel model's upstream took longer than the fusion panel timeout (large prompts, slow provider, streaming stall); the panel promise lost the race and got a __timeout marker; network path to that provider is slow or the model is very long-context.

Common situations: Including a slow local model (ollama on CPU) in a fusion panel with cloud models; provider cold-start latency; long system prompts pushing generation past the deadline; regional network degradation; a hung upstream connection that never errors but never completes.

Understand the failure class

Related errors


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