{"record":{"id":"66ab7f1b0dfb46b9","repo":"odysseus-dev/odysseus","slug":"http-res-status-res-statustext-msg-m","errorCode":null,"errorMessage":"HTTP ${res.status} ${res.statusText}${msg ? `: ${msg}` : ''}","messagePattern":"HTTP (.+?) (.+?)(.+?)` : ''\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/cookbook-hwfit.js","lineNumber":853,"sourceCode":"      const _fitOnly = (() => { try { return localStorage.getItem('hwfit_fit_only_v1') === '1'; } catch { return false; } })();\n      if (_fitOnly) params.set('fit_only', '1');\n    }\n    const endpoint = isImageMode ? `/api/hwfit/image-models?${params}` : `/api/hwfit/models?${params}`;\n    const res = await fetch(endpoint);\n    // A newer scan started while this one was in flight (user switched servers\n    // mid-probe) — drop this stale response so it can't clobber the new one.\n    if (_tk !== _hwfitFetchToken) { try { wp.destroy(); } catch {} return; }\n    if (!res.ok) {\n      const body = await res.text().catch(() => '');\n      let msg = '';\n      try {\n        const payload = JSON.parse(body);\n        msg = payload && (payload.detail || payload.error || payload.message);\n      } catch {\n        msg = body;\n      }\n      msg = typeof msg === 'string' ? msg.trim() : '';\n      throw new Error(`HTTP ${res.status} ${res.statusText}${msg ? `: ${msg}` : ''}`);\n    }\n    let data = await res.json();\n    if (_tk !== _hwfitFetchToken) { try { wp.destroy(); } catch {} return; }\n    if (!isImageMode && quantPref && !data.error && Array.isArray(data.models) && data.models.length === 0) {\n      const fallbackParams = new URLSearchParams(params);\n      fallbackParams.delete('quant');\n      const fallbackRes = await fetch(`/api/hwfit/models?${fallbackParams}`);\n      if (_tk !== _hwfitFetchToken) { try { wp.destroy(); } catch {} return; }\n      if (fallbackRes.ok) {\n        const fallbackData = await fallbackRes.json();\n        if (!fallbackData.error && Array.isArray(fallbackData.models) && fallbackData.models.length > 0) {\n          data = fallbackData;\n          const quantSel = document.getElementById('hwfit-quant');\n          if (quantSel) quantSel.value = '';\n        }\n      }\n    }\n    // Normalize image model fields to match LLM renderer expectations.","sourceCodeStart":835,"sourceCodeEnd":871,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/cookbook-hwfit.js#L835-L871","documentation":"Error thrown by the hardware-fit model scan in the cookbook when GET /api/hwfit/models answers non-OK. It makes a best effort to surface the server's detail/error/message JSON field (or raw body) alongside the status and status text, so the message usually carries the real backend reason (e.g. upstream HF/OSH API failure).","triggerScenarios":"GET /api/hwfit/models?<params> returns 5xx because the backend cannot reach huggingface.co (offline, rate-limited, proxy blocked), 4xx for invalid params (bad quant filter, unknown hardware profile), or the body is HTML from an intermediary so msg falls back to raw text.","commonSituations":"No internet or corporate proxy blocks HF; quant filter so restrictive the upstream returns zero and a fallback without quant is attempted; backend dependency for model metadata changed its response shape; request raced with a new fetch (token check) leaving stale UI.","solutions":["Read the ': <msg>' part of the message — it is the backend's own error text; act on it (connectivity, param validity)","curl the same /api/hwfit/models URL with the identical query params to see the raw status/body","If network-related, fix outbound access (DNS/proxy/firewall) on the server host","If the quant filter caused it, relax or clear the quant preference so the non-quant fallback path is not needed"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  if (!res.ok) {\n    const body = await res.text().catch(() => '');\n    let msg = '';\n    try { msg = JSON.parse(body)?.detail || ''; } catch { msg = body; }\n    throw new Error(`HTTP ${res.status} ${res.statusText}${msg ? ': ' + String(msg).slice(0, 200) : ''}`);\n  }\n  const data = await res.json();\n  // ...render\n} catch (e) {\n  if (e.name === 'AbortError') return;\n  renderModelScanError(e.message);\n}","preventionTips":["Check the fetch token (_hwfitFetchToken) after every await to drop stale responses — already done, keep it","Truncate long error bodies so HTML proxy pages don't blow up the UI","Fall back to a no-quant query (pattern already present) before surfacing empty results"],"tags":["fetch","http-error","model-scan","huggingface","cookbook"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}