decolua/9router · warning

HTTP ${response.status}

Error message

HTTP ${response.status}

What it means

syncModelCatalog fetches the remote model catalog with ETag-based caching. Any non-ok, non-304 HTTP response from the catalog server is rethrown as `HTTP <status>` after the fetch resolves.

Source

Thrown at src/lib/modelCatalog/sync.js:182

    }
  }
  return entries;
}

// Run one sync. Returns a summary, or null when it could not complete.
export async function syncModelCatalog() {
  if (state.running) return null;
  state.running = true;
  try {
    const headers = { accept: "application/json" };
    if (state.etag) headers["if-none-match"] = state.etag;
    const response = await fetch(CATALOG_URL, { headers, signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });

    let result;
    if (response.status === 304) {
      result = { status: "unchanged" };
    } else if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    } else {
      // ~23ms to parse, once a day, on a server that is otherwise idle at this
      // point — not worth a worker thread.
      const catalog = await response.json();
      const etag = response.headers.get("etag") || null;
      const entries = await collectEntries();
      const { models, providers } = build(catalog, entries);
      const serialized = JSON.stringify({ v: 1, etag, syncedAt: Date.now(), models, providers });

      writeAtomic(CATALOG_FILE, serialized);
      writeAtomic(CATALOG_RAW_FILE, JSON.stringify(slim(catalog)));

      state.etag = etag;
      invalidateCatalog();
      result = {
        status: "updated",
        etag,
        bytes: Buffer.byteLength(serialized),

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Retry later — the sync is periodic and non-fatal; the app keeps working with the previously cached catalog.
  2. Check https://status or the catalog URL manually (curl -I $CATALOG_URL) to see whether the outage is server-side.
  3. If behind a proxy, fix proxy/firewall rules so the request reaches the real host.
  4. Update the app in case CATALOG_URL changed; as a last resort the catalog can be refreshed by a new sync once the server recovers.
Defensive patterns

Strategy: retry

Try / catch

for (let attempt = 0; attempt < 3; attempt++) {
  try {
    const r = await syncModelCatalog();
    break;
  } catch (err) {
    if (/^HTTP \d+$/.test(err.message) && attempt < 2) {
      await new Promise(r => setTimeout(r, 2 ** attempt * 1000)); // backoff, catalog sync is non-fatal
      continue;
    }
    console.warn("model catalog sync failed, using cached catalog:", err.message);
  }
}

Prevention

When it happens

Trigger: The catalog endpoint returns 4xx/5xx: 403/429 (rate limit or blocked), 404 (CATALOG_URL moved), 500/502/503 (server outage). 304 is handled as success (unchanged) and never reaches this throw.

Common situations: Catalog host temporarily down or behind a failing CDN; corporate proxy/firewall intercepting and returning an error page; hardcoded CATALOG_URL outdated after the project moved hosting; rate limiting from running many instances behind one IP.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/a47c6b74750a2a93. Report an issue: GitHub.