AlexsJones/llmfit · error · Error

Request failed with status ${response.status}.

Error message

Request failed with status ${response.status}.

What it means

Fallback branch of parseJsonOrThrow(): the response had a non-2xx status (response.ok === false) AND the parsed JSON body had no `error` field, so the generic status line is used. It is the llmfit web client's way of surfacing an HTTP-level failure from /api/v1/system, /api/v1/models, /api/v1/runtimes, /api/v1/installed, /api/v1/download, /api/v1/download/{id}/status, or /api/v1/plan when the server did not attach a structured message.

Source

Thrown at llmfit-web/src/api.js:115

      params.set('max_context', String(parsed));
    }
  }

  appendSimulationParams(params, simulation);
  return params.toString();
}

async function parseJsonOrThrow(response) {
  let payload;
  try {
    payload = await response.json();
  } catch (err) {
    throw new Error('Server returned an invalid JSON response.');
  }

  if (!response.ok) {
    const message = payload?.error || `Request failed with status ${response.status}.`;
    throw new Error(message);
  }

  return payload;
}

export async function fetchSystemInfo(simulation = {}, signal) {
  const query = appendSimulationParams(new URLSearchParams(), simulation).toString();
  const path = query ? `/api/v1/system?${query}` : '/api/v1/system';
  const response = await fetch(path, { signal });
  return parseJsonOrThrow(response);
}

export async function fetchModels(filters, simulation = {}, signal) {
  const query = buildModelsQuery(filters, simulation);
  const path = query ? `/api/v1/models?${query}` : '/api/v1/models';
  const response = await fetch(path, { signal });
  return parseJsonOrThrow(response);
}

View on GitHub (pinned to a9ac7ed91c)

Solutions

  1. Wrap the call and log response.status alongside the message so you know which HTTP code fired it.
  2. Check the llmfit server logs at the same timestamp - a 4xx/5xx there explains the missing body.
  3. Validate the arguments you pass (model exists in /api/v1/models, download id came from a live startDownload response).
  4. If you control the server code, make failing handlers return `{"error": "..."}` so clients get the specific message instead of this fallback.

Example fix

// before
const response = await fetch(`/api/v1/download/${encodeURIComponent(id)}/status`, { signal });
return parseJsonOrThrow(response);

// after - surface status and body when the server omits payload.error
const response = await fetch(`/api/v1/download/${encodeURIComponent(id)}/status`, { signal });
if (!response.ok) {
  const body = await response.text();
  throw new Error(`Status ${response.status} for download ${id}: ${body.slice(0, 200) || '(empty body)'}`);
}
return response.json();
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return await fetchDownloadStatus(id, signal);
} catch (err) {
  const m = err.message.match(/^Request failed with status (\d+)\.$/);
  if (m) {
    const status = Number(m[1]);
    if (status === 404) return null;          // unknown/expired download id -> treat as gone
    if (status >= 500) throw new Error('llmfit server error, retry later');
  }
  throw err;
}

Prevention

When it happens

Trigger: POST /api/v1/download with a model or runtime the server rejects without an error body; GET /api/v1/download/{id}/status after the server restarted and lost the download id; POST /api/v1/plan with malformed context/quant values; any 404/405/500 from the Axum router whose body is empty or lacks payload.error.

Common situations: Passing a model name that is not in the catalog; polling download status with a stale id after a server restart; query params rejected by server-side validation; a handler panicking (500) before it can build a JSON error response.

Related errors


AI-assisted analysis of AlexsJones/llmfit@a9ac7ed91c (2026-08-16). Data as JSON: /api/errors/402ba28006e29b74. Report an issue: GitHub.