odysseus-dev/odysseus · warning · Error

HTTP ${res.status} ${res.statusText}${msg ? `: ${msg}` : ''}

Error message

HTTP ${res.status} ${res.statusText}${msg ? `: ${msg}` : ''}

What it means

Error thrown when the cached-model scan for the serve panel fails at the HTTP level: GET /api/model/cached<params> answered non-OK. The handler reads the body text, tries JSON detail/error/message, and appends whatever it found to the status line, then renders a 'Cached model scan failed' panel with a Retry button.

Source

Thrown at static/js/cookbookServe.js:4213

      setTimeout(() => {
        if (list.querySelector('.serve-empty-auto-scan')) _fetchCachedModels(true);
      }, 60);
      const tagContainer = document.getElementById('serve-tags');
      if (tagContainer) tagContainer.innerHTML = '';
      return;
    }
    const res = await fetch(`/api/model/cached${params}`);
    if (!res.ok) {
      const body = await res.text().catch(() => '');
      let msg = '';
      try {
        const payload = JSON.parse(body);
        msg = payload && (payload.detail || payload.error || payload.message);
      } catch {
        msg = body;
      }
      msg = typeof msg === 'string' ? msg.trim() : '';
      throw new Error(`HTTP ${res.status} ${res.statusText}${msg ? `: ${msg}` : ''}`);
    }
    const data = await res.json();
    if (data && data.error) throw new Error(data.error);
    _writeCachedModelScan(scanSig, data);
    _dlWp.destroy();
    _renderCachedModelsData(list, data, host);
  } catch (e) {
    _dlWp.destroy();
    list.innerHTML = `<div class="hwfit-loading" style="flex-direction:column;gap:8px;text-align:center;"><div style="color:var(--red);font-weight:600;">Cached model scan failed</div><div style="font-size:11px;opacity:0.65;max-width:420px;line-height:1.4;">${esc(e.message)}</div><button type="button" class="hwfit-gpu-btn serve-empty-scan-btn" style="height:26px;padding:3px 10px;">Retry</button></div>`;
    list.querySelector('.serve-empty-scan-btn')?.addEventListener('click', () => {
      _fetchCachedModels(true);
    });
  }
}

/** Filter presets matching a model repo */
function _presetsForModel(presets, repo) {
  const short = repo.split('/').pop();

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Use the Retry button after fixing the underlying cause identified in the ': <msg>' suffix
  2. curl -i the same /api/model/cached URL with params to see the full body
  3. Verify filesystem permissions on the models cache directory (and SSH reachability if host-scoped)
  4. Check backend logs for the scan exception
Defensive patterns

Strategy: retry

Try / catch

try {
  const res = await fetch(`/api/model/cached${params}`);
  if (!res.ok) {
    const body = await res.text().catch(() => '');
    let msg = '';
    try { msg = JSON.parse(body)?.detail || ''; } catch { msg = body; }
    throw new Error(`HTTP ${res.status} ${res.statusText}${msg ? ': ' + String(msg).trim().slice(0, 200) : ''}`);
  }
  const data = await res.json();
  if (data?.error) throw new Error(data.error);
  _writeCachedModelScan(scanSig, data);
  _dlWp.destroy();
  _renderCachedModelsData(list, data, host);
} catch (e) {
  _dlWp.destroy();
  renderScanFailureWithRetry(list, e.message, () => _fetchCachedModels(true));
}

Prevention

When it happens

Trigger: GET /api/model/cached returns 500 (backend scan of the models directory crashed — permission denied, disk error, huge directory timeout), 502/504 behind a proxy, or the scan is pointed at a remote host via params whose SSH connection failed.

Common situations: Models directory on a network mount that dropped; scan of a remote cache host whose SSH credentials changed; response body too large/slow triggering gateway timeout; backend updated and the route contract moved.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/f1202a5124c4c858. Report an issue: GitHub.