jackwener/OpenCLI · error · CommandExecutionError

${label} returned HTTP ${resp.status}${detail}

Error message

${label} returned HTTP ${resp.status}${detail}

What it means

openalexFetch wraps every OpenAlex REST call and converts non-ok HTTP statuses (other than 404/429, which get their own errors) into a CommandExecutionError carrying the status code plus any "message" field extracted from the error body. It exists so callers get a consistent, labeled failure instead of a raw fetch/HTTP object. The interpolated detail comes from parsing the response text for a JSON "message" key.

Source

Thrown at clis/openalex/utils.js:109

    }
    if (resp.status === 404) {
        throw new EmptyResultError(label, `OpenAlex returned 404 for ${url}.`);
    }
    if (resp.status === 429) {
        throw new CommandExecutionError(
            `${label} returned HTTP 429 (rate limited)`,
            'OpenAlex throttles unauthenticated traffic; wait a few seconds and retry, or set OPENALEX_MAILTO.',
        );
    }
    if (!resp.ok) {
        let detail = '';
        try {
            const text = await resp.text();
            const match = text.match(/"message"\s*:\s*"([^"]+)"/);
            if (match) detail = ` (${match[1]})`;
        }
        catch { /* ignore */ }
        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}${detail}`);
    }
    let body;
    try {
        body = await resp.json();
    }
    catch (err) {
        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
    }
    return body;
}

/** Strip the `https://openalex.org/` prefix if present so columns surface just the bare id. */
export function bareId(value) {
    const s = String(value ?? '').trim();
    if (!s) return '';
    return s.replace(/^https?:\/\/(?:api\.)?openalex\.org\//i, '').replace(/^works\//i, '');
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the interpolated detail in the message — it contains OpenAlex's own error "message" from the response body, which usually names the bad parameter.
  2. Print/log the full URL that was fetched and validate each query parameter (filters, per-page, sort) against the OpenAlex API docs.
  3. Retry once after a short wait in case of a transient 5xx, and check the OpenAlex status page.
  4. Escape and re-encode user-supplied query terms with encodeURIComponent before building the URL.

Example fix

// before
const url = `${OPENALEX_BASE}/works?filter=${rawUserFilter}`;
// after
const url = `${OPENALEX_BASE}/works?filter=${encodeURIComponent(rawUserFilter)}`;
Defensive patterns

Strategy: try-catch

Validate before calling

function validateOpenAlexQuery(params) {
  for (const [k, v] of Object.entries(params)) {
    if (v == null || v === '') throw new Error(`openalex param "${k}" is empty`);
  }
  return true;
}

Type guard

function isHttpError(e) {
  return e instanceof Error && /returned HTTP \d+/.test(e.message);
}

Try / catch

try {
  const body = await openalexFetch(url, 'openalex works');
} catch (e) {
  const m = e.message.match(/returned HTTP (\d+)/);
  if (m && Number(m[1]) >= 500) { /* retry after delay */ }
  else { /* surface e.message (contains API detail) to the user */ }
}

Prevention

When it happens

Trigger: An OpenAlex request resolves but returns a non-ok, non-404/429 status — e.g. HTTP 400 for a malformed query string, 403 for a blocked user agent, or 5xx when OpenAlex is degraded. Any command that calls openalexFetch (works lookup by id/DOI, search listings) can hit it.

Common situations: A malformed filter/query parameter produces 400 from api.openalex.org; a corporate proxy or firewall returns 403; OpenAlex has a transient 5xx outage; an invalid entity id path slips past validation and yields an unexpected status.

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 jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/f0b85a391ef3b4b7. Report an issue: GitHub.