{"record":{"id":"808cc4ddd998a87d","repo":"decolua/9router","slug":"fusion-panel-model-failed","errorCode":null,"errorMessage":"FUSION Panel ${model} failed","messagePattern":"FUSION Panel (.+?) failed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"open-sse/services/combo.js","lineNumber":593,"sourceCode":"    panelBody.messages = flattenToolHistory(panelBody.messages);\n  } else if (Array.isArray(panelBody.input)) {\n    panelBody.input = flattenToolHistory(panelBody.input);\n  }\n\n  const t0 = Date.now();\n  const calls = panel.map((m) => withTimeout(handleSingleModel(panelBody, m, true), cfg.panelHardTimeoutMs));\n  const settled = await collectPanel(calls, { ...cfg, minPanel });\n  log.info(\"FUSION\", `fan-out collected in ${Date.now() - t0}ms`);\n\n  // 2. Collect successful answers.\n  const answers = [];\n  for (let i = 0; i < settled.length; i++) {\n    const res = settled[i];\n    const model = panel[i];\n    if (!res) { log.warn(\"FUSION\", `Panel ${model} dropped (straggler/timeout)`); continue; }\n    if (res.__timeout) { log.warn(\"FUSION\", `Panel ${model} timed out`); continue; }\n    if (res.__error) { log.warn(\"FUSION\", `Panel ${model} threw`, { error: res.__error?.message || String(res.__error) }); continue; }\n    if (!res.ok) { log.warn(\"FUSION\", `Panel ${model} failed`, { status: res.status }); continue; }\n    try {\n      const json = await res.clone().json();\n      const text = extractPanelText(json);\n      if (text) {\n        answers.push({ model, text });\n        log.info(\"FUSION\", `Panel ${model} ok (${text.length} chars)`);\n      } else {\n        log.warn(\"FUSION\", `Panel ${model} returned empty content`);\n      }\n    } catch (e) {\n      log.warn(\"FUSION\", `Panel ${model} unparseable`, { error: e.message || String(e) });\n    }\n  }\n\n  // 3. Degrade gracefully when the panel is too thin to fuse.\n  if (answers.length === 0) {\n    log.warn(\"FUSION\", \"All panel models failed\");\n    return new Response(","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/services/combo.js#L575-L611","documentation":"In the FUSION combo service, each panel model is called in parallel and its response collected. When a panel's HTTP response is not ok (res.ok false), the panel is skipped with this warning rather than aborting the whole fusion request. It is a per-panel degradation log, not a fatal throw.","triggerScenarios":"A panel model upstream returned a non-2xx status (4xx/5xx) during parallel fan-out — e.g. upstream 429 rate limit, 401/403 bad/expired credentials, 404 unknown model alias, or 5xx upstream outage.","commonSituations":"One account in the panel hit its rate limit while others succeed; an API key was rotated/revoked; a model name in the fusion panel config no longer exists on its provider; provider outage causes 502/503.","solutions":["Check the `status` field in the warn log to see which HTTP status the panel got and fix that specific provider (key, quota, model name)","Verify each panel model in the fusion config exists and is enabled for the configured account","If 429: reduce panel size or request rate, or add more accounts for that provider","If 401/403: re-authenticate or re-enter the API key for that provider in the dashboard","If all panels fail, the request degrades to a 503 — see 'All fusion panel models failed'"],"exampleFix":"// before: panel references a retired model\npanel: [\"claude-3-opus-20240229\", \"gpt-4o\"]\n// after: use a valid, current model id\npanel: [\"claude-sonnet-4-5\", \"gpt-4o\"]","handlingStrategy":"fallback","validationCode":"const panel = body.panel || [];\nif (!panel.length) throw new Error('fusion panel is empty — nothing to call');\n// optionally preflight each model with a cheap GET /models check","typeGuard":"const isUsablePanelResponse = (res) => Boolean(res) && !res.__timeout && !res.__error && res.ok;","tryCatchPattern":"try {\n  const res = await fetchWithTimeout(url, { timeoutMs: PANEL_TIMEOUT });\n  if (!res.ok) console.warn(`panel ${model} failed: ${res.status}`); // already degraded, no throw\n  else return await res.json();\n} catch (e) {\n  console.warn(`panel ${model} threw: ${e.message}`);\n  return null; // fusion continues with remaining panels\n}","preventionTips":["Keep at least 2-3 independent providers in the fusion panel","Monitor the per-panel warn logs for recurring status codes","Rotate/refresh provider credentials before expiry","Pin valid, current model ids in the panel config"],"tags":["fusion","upstream","http-status","rate-limit"],"backgroundTag":"upstream-429-rate-limited","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}