tinyhumansai/openhuman · error

HTTP error! status: ${response.status}

Error message

HTTP error! status: ${response.status}

What it means

Thrown by the generic fetch wrapper in apiClient when the response is NOT ok AND the content-type is not application/json — the two preconditions for trying to parse a structured ApiError. Because the body is not JSON, the status code is the only information available, hence the generic template `HTTP error! status: ${response.status}`.

Source

Thrown at app/src/services/apiClient.ts:99

    }

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);

    const config: RequestInit = { method, headers, signal: controller.signal };

    if (body && method !== 'GET') {
      config.body = JSON.stringify(body);
    }

    try {
      const response = await fetch(url, config);

      // Handle non-JSON responses
      const contentType = response.headers.get('content-type');
      if (!contentType || !contentType.includes('application/json')) {
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        return {} as T;
      }

      const data = await response.json();

      // Handle error responses
      if (!response.ok) {
        const error: ApiError = data.error
          ? { success: false, error: data.error, message: data.message }
          : { success: false, error: `HTTP ${response.status}: ${response.statusText}` };
        throw error;
      }

      return data as T;
    } catch (error) {
      // Re-throw API errors as-is
      if (error && typeof error === 'object' && 'error' in error) {

View on GitHub (pinned to a221052e0d)

Solutions

  1. Read the status from the message: 502/503/504 are infra/proxy — retry shortly or check the backend status page; 404 usually means a wrong base URL
  2. Verify the backend URL configuration (VITE_* config via app/src/utils/config.ts / .env files) points at the real API host
  3. curl -i the same URL from the same machine and inspect what non-JSON body comes back and from which hop
  4. Retry with backoff for 5xx gateway codes — these are typically transient
  5. If a proxy strips JSON, fix the proxy/TLS-inspection exemption for the API host

Example fix

// before
const data = await apiClient.request<T>('/teams');

// after
try {
  const data = await apiClient.request<T>('/teams');
} catch (e) {
  if (e instanceof Error && /HTTP error! status: 5\d\d/.test(e.message)) {
    return retryWithBackoff(() => apiClient.request<T>('/teams'));
  }
  throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight connectivity sanity: an infra/proxy error page usually fails a cheap probe too
const ok = await fetch(baseUrl, { method: 'HEAD' }).then(r => r.ok).catch(() => false);
if (!ok) skipCloudCallAndWarn();

Type guard

function isNonJsonHttpError(e: unknown): e is Error {
  return e instanceof Error && /HTTP error! status: \d+/.test(e.message);
}

Try / catch

try {
  return await api.request<T>(path, init);
} catch (e) {
  const status = e instanceof Error ? Number(/status: (\d+)/.exec(e.message)?.[1]) : 0;
  if (status >= 500 && attempt < 3) {
    await delay(2 ** attempt * 500);
    return api.request<T>(path, init); // gateway errors are usually transient
  }
  if (status === 404) throw new Error(`API base URL may be wrong: ${baseUrl}`);
  throw e;
}

Prevention

When it happens

Trigger: The cloud backend (or anything in front of it) returns an HTML error page with 502/503/504 (CDN/proxy like Cloudflare, maintenance page, gateway timeout), a plain-text 500 from an infra component, or the configured base URL points at a server that is not the API at all.

Common situations: Backend outage or deploy window surfaced as proxy HTML; wrong BACKEND/API base URL in app config or .env (hitting a marketing site or empty host); corporate TLS-inspection proxy replacing responses; backend returning empty bodies on 5xx.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/7d40963b244955c9. Report an issue: GitHub.