{"record":{"id":"a5b2787968bfddee","repo":"mudler/LocalAI","slug":"status-http-statusres-status","errorCode":null,"errorMessage":"status: HTTP ${statusRes.status}","messagePattern":"status: HTTP (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"core/http/react-ui/src/pages/Middleware.jsx","lineNumber":84,"sourceCode":"  const initialTab = searchParams.get('tab') || localStorage.getItem('middleware-tab') || 'filtering'\n  const [activeTab, setActiveTab] = useState(TABS.some(t => t.id === initialTab) ? initialTab : 'filtering')\n  const selectTab = (id) => {\n    setActiveTab(id)\n    localStorage.setItem('middleware-tab', id)\n    setSearchParams({ tab: id })\n  }\n\n  // silent=true on background polls: skips the loading spinner and\n  // suppresses toast spam if the server is briefly unreachable.\n  const fetchAll = useCallback(async (silent = false) => {\n    if (!silent) setLoading(true)\n    try {\n      const [statusRes, eventsRes, decisionsRes] = await Promise.all([\n        fetch(apiUrl('/api/middleware/status')),\n        fetch(apiUrl('/api/pii/events?limit=100')),\n        fetch(apiUrl('/api/router/decisions?limit=100')),\n      ])\n      if (!statusRes.ok) throw new Error(`status: HTTP ${statusRes.status}`)\n      const statusData = await statusRes.json()\n      setStatus(statusData)\n      if (eventsRes.ok) {\n        const data = await eventsRes.json()\n        setEvents(data.events || [])\n      }\n      if (decisionsRes.ok) {\n        const data = await decisionsRes.json()\n        setDecisions(data.decisions || [])\n      }\n    } catch (err) {\n      if (!silent) addToast(`Failed to load middleware status: ${err.message}`, 'error')\n    } finally {\n      if (!silent) setLoading(false)\n    }\n  }, [addToast])\n\n  useEffect(() => { fetchAll() }, [fetchAll])","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/core/http/react-ui/src/pages/Middleware.jsx#L66-L102","documentation":"Thrown by the Middleware dashboard's fetchAll() when GET /api/middleware/status returns a non-2xx status. The status endpoint is treated as fatal (it defines the page), while /api/pii/events and /api/router/decisions failures are silently ignored, so this error fires only when the middleware status route itself fails. In silent background polls the error is swallowed (no toast); on the initial load it surfaces as a toast.","triggerScenarios":"Calling GET /api/middleware/status and receiving 404 (route/middleware not built or disabled), 401/403 (auth enabled and token expired between page load and fetch), 500 (middleware subsystem crash), or the API_PREFIX/proxy misrouting apiUrl() to a path the server does not serve.","commonSituations":"Reverse proxy stripping or rewriting the /api prefix; LocalAI started with middleware features compiled/disabled; expired session on a long-open tab where the silent poll starts failing after the initial load succeeded; gateway timeout when middleware status collection blocks.","solutions":["curl -i http://<host>:<port>/api/middleware/status directly and check the status code and body","If 401/403, re-authenticate or refresh the token; the silent poll suppresses auth failures so check the network tab","If 404, verify the server build includes the middleware routes and that apiUrl() prefix matches the served path","If 5xx, inspect the LocalAI server logs for the middleware status handler panic"],"exampleFix":"// before\nif (!statusRes.ok) throw new Error(`status: HTTP ${statusRes.status}`)\n\n// after: include response body detail when available\nif (!statusRes.ok) {\n  let detail = ''\n  try { detail = (await statusRes.json())?.error || '' } catch { /* non-JSON body */ }\n  throw new Error(`status: HTTP ${statusRes.status}${detail ? `: ${detail}` : ''}`)\n}","handlingStrategy":"retry","validationCode":"// Before mounting, confirm the route exists so the initial load fails fast and clearly\nasync function middlewareStatusReachable(apiBase) {\n  try {\n    const res = await fetch(`${apiBase}/api/middleware/status`)\n    return res.ok\n  } catch { return false }\n}","typeGuard":null,"tryCatchPattern":"// Distinguish transient from permanent: silent polls retry, user-triggered loads toast\ntry {\n  await fetchAll(false)\n} catch (err) {\n  if (/HTTP 5\\d\\d/.test(err.message)) setTimeout(() => fetchAll(true), 5000) // server hiccup: back off and retry silently\n  else addToast(`Middleware unavailable: ${err.message}`, 'error') // 401/404: needs user action\n}","preventionTips":["Keep the /api prefix consistent between apiUrl() and the reverse proxy","Run auth token refresh before long-lived pages that poll","Treat 5xx on background polls as transient with backoff, 401/403 as session expiry requiring re-auth"],"tags":["http","middleware","react-ui","polling"],"backgroundTag":null,"analyzedSha":"44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26","analyzedAt":"2026-08-15T10:13:50.291Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}