odysseus-dev/odysseus · error · Error

HTTP ${res.status}${body ? ': ' + body.slice(0, 160) : ''}

Error message

HTTP ${res.status}${body ? ': ' + body.slice(0, 160) : ''}

What it means

Thrown in markdown.js when adding a model endpoint via POST /api/model-endpoints fails. The first 160 chars of the response body are appended to the status. The button UI is restored and the error surfaced via showError in the catch, so the 'Add endpoint' affordance recovers cleanly.

Source

Thrown at static/js/markdown.js:1046

    const parsed = new URL(baseUrl, window.location.origin);
    const fd = new FormData();
    fd.append('base_url', baseUrl);
    fd.append('name', _endpointNameFromUrl(baseUrl));
    fd.append('model_type', 'llm');
    fd.append('endpoint_kind', 'auto');
    fd.append('skip_probe', 'true');
    if (/^(localhost|127\.0\.0\.1|0\.0\.0\.0)$/i.test(parsed.hostname)) {
      fd.append('container_local', 'true');
    }
    const res = await fetch('/api/model-endpoints', {
      method: 'POST',
      credentials: 'same-origin',
      body: fd,
    });
    if (!res.ok) {
      const body = await res.text().catch(() => '');
      throw new Error(`HTTP ${res.status}${body ? ': ' + body.slice(0, 160) : ''}`);
    }
    btn.classList.add('added');
    btn.innerHTML = '<span aria-hidden="true">✓</span><span>Added</span>';
    window.dispatchEvent(new CustomEvent('ge:model-endpoints-updated', { detail: { baseUrl } }));
    if (window.modelsModule?.refreshModels) await window.modelsModule.refreshModels(true);
    if (window.sessionModule?.updateModelPicker) window.sessionModule.updateModelPicker();
    uiModule.showToast?.(`Model endpoint added: ${_endpointNameFromUrl(baseUrl)}`);
  } catch (err) {
    btn.disabled = false;
    btn.innerHTML = original;
    uiModule.showError?.(`Add endpoint failed: ${err.message || err}`);
  }
}

(function _watchModelEndpointLinks() {
  if (window._modelEndpointLinkWatcherWired) return;
  window._modelEndpointLinkWatcherWired = true;

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Verify the URL opens in a browser/curl from the same machine, including port and /v1 suffix if required.
  2. Read the truncated body text — FastAPI validation errors name the offending field.
  3. Remove the existing duplicate endpoint first if the server rejects re-registration.
  4. For Docker setups, use the container-reachable address (host.docker.internal or service name).
Defensive patterns

Strategy: validation

Validate before calling

let parsed; try { parsed = new URL(baseUrl); } catch { showError('Invalid URL'); return; }
if (!/^https?:$/.test(parsed.protocol)) { showError('Use http(s) URL'); return; }

Type guard

const isEndpointPayload = (fd) => fd instanceof FormData && fd.get('base_url');

Try / catch

try { ... } catch (err) { btn.disabled = false; btn.innerHTML = original; uiModule.showError(`Add endpoint failed: ${err.message}`); }

Prevention

When it happens

Trigger: Submitting an endpoint URL that fails server-side validation (unreachable base URL even with skip_probe=true, malformed URL, duplicate endpoint); a provider value the backend rejects; container_local flag mismatch for localhost URLs.

Common situations: Adding an Ollama/LM Studio URL with wrong port or scheme; adding an endpoint that duplicates one already registered; pointing at a container-internal address without the container_local hint because the hostname regex did not match (e.g. host.docker.internal).

Related errors


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