Hmbown/CodeWhale · error

detail || ("HTTP " + res.status)

Error message

detail || ("HTTP " + res.status)

What it means

The generic api() helper in the mobile runtime throws an Error carrying the response's error message (extracted from JSON `error.message`) or, if the body is not parseable/useful, a plain "HTTP <status>" string for any non-ok response (with 401 additionally clearing the saved session).

Solutions

  1. Read the thrown message: if it is "HTTP 401", reconnect the session with a fresh Runtime token.
  2. If "HTTP 404" or 5xx, check the Runtime server is running the version matching the mobile page and that the requested thread/turn exists.
  3. Retry after reconnecting; clear the session on 401 so the user re-authenticates.

Example fix

// before
const data = await api('/v1/threads/' + id);
// after
try {
  const data = await api('/v1/threads/' + id);
} catch (e) {
  if (String(e.message) === 'HTTP 401') await connectMobileSession();
  else showError(e.message);
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Try / catch

try {
  const data = await api(url, opts);
} catch (e) {
  if (String(e.message) === 'HTTP 401') { clearMobileSession(); await connectMobileSession(); }
  else displayError(e.message);
}

Prevention

When it happens

Trigger: Any api() call where the server responds with a non-ok status: 401 (bad/expired proof), 404 (unknown thread/turn path), 5xx (Runtime error), or an empty body.

Common situations: Expired session proof giving 401; Runtime not running or restarting (connection failures/5xx); calling an endpoint path that does not exist on the deployed version.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/0235c740715ec310. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/runtime_mobile.html:367

    function headers(extra = {}) {
      const out = Object.assign({ "Content-Type": "application/json" }, extra);
      if (state.requestProof) out[MOBILE_REQUEST_HEADER] = state.requestProof;
      return out;
    }

    async function api(path, options = {}) {
      const res = await fetch(path, Object.assign({}, options, {
        credentials: "same-origin",
        headers: headers(options.headers || {})
      }));
      if (!res.ok) {
        if (res.status === 401) clearMobileSession();
        let detail = await res.text();
        try {
          const parsed = JSON.parse(detail);
          detail = parsed.error?.message || detail;
        } catch (_) {}
        throw new Error(detail || ("HTTP " + res.status));
      }
      if (res.status === 204) return null;
      return res.json();
    }

    async function connectMobileSession() {
      const runtimeToken = token();
      if (!runtimeToken) throw new Error("Enter a Runtime token to connect once");
      let res;
      try {
        res = await fetch("/__codewhale/mobile/session", {
          method: "POST",
          credentials: "same-origin",
          headers: { "Authorization": "Bearer " + runtimeToken }
        });
      } finally {
        $("token").value = "";
      }

View on GitHub (pinned to 73e0f67d83)