jackwener/OpenCLI · error · CommandExecutionError

${label} returned an error: ${body.error}

Error message

${label} returned an error: ${body.error}

What it means

When the Semantic Scholar response parses as JSON but contains a truthy `error` field (API-level error object inside a 200 or ok response), s2Fetch surfaces it as CommandExecutionError `${label} returned an error: ${body.error}`. This is the API's own application error, not a transport failure.

Source

Thrown at clis/semanticscholar/utils.js:131

        throw new EmptyResultError(label, `Semantic Scholar returned 404 for ${url}.`);
    }
    if (resp.status === 429) {
        throw new CommandExecutionError(
            `${label} returned HTTP 429 (rate limited)`,
            'Semantic Scholar throttles anonymous traffic; set SEMANTIC_SCHOLAR_API_KEY (free at https://www.semanticscholar.org/product/api) or wait a minute and retry.',
        );
    }
    if (!resp.ok) {
        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
    }
    let body;
    try {
        body = await resp.json();
    } catch (err) {
        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
    }
    if (body && typeof body === 'object' && body.error) {
        throw new CommandExecutionError(`${label} returned an error: ${body.error}`);
    }
    return body;
}

/** Return the AI-generated one-line summary if present, else ''. */
export function tldrText(tldr) {
    if (tldr && typeof tldr === 'object' && typeof tldr.text === 'string') {
        return tldr.text.trim();
    }
    return '';
}

/** First author display name, or '' when authors is missing. */
export function firstAuthorName(authors) {
    if (!Array.isArray(authors) || !authors.length) return '';
    const first = authors[0];
    if (first && typeof first === 'object' && typeof first.name === 'string') {
        return first.name.trim();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read body.error from the message for the API's own explanation.
  2. For recommendations errors, try a different or better-known paper ref (DOI or canonical S2 paperId).
  3. Re-check the query string: remove invalid fields or parameters the API flagged.
  4. Retry later if the error indicates a backend problem; otherwise fix the request payload.

Example fix

// before
const recs = await s2Fetch(`${S2_REC_BASE}/papers/forpaper/${ref}?fields=title`, 'recommendations');
// after: fall back when the API reports an in-band error
try {
  const recs = await s2Fetch(`${S2_REC_BASE}/papers/forpaper/${ref}?fields=title`, 'recommendations');
} catch (e) {
  if (/returned an error/.test(e.message)) return []; // no recommendations available
  throw e;
}
Defensive patterns

Strategy: fallback

Type guard

function hasApiError(body) {
  return body !== null && typeof body === 'object' && 'error' in body && Boolean(body.error);
}

Try / catch

try {
  return await s2Fetch(url, 'recommendations');
} catch (err) {
  if (/returned an error/.test(err.message)) {
    return { recommendations: [] }; // graceful empty fallback
  }
  throw err;
}

Prevention

When it happens

Trigger: The graph/recommendations API returns {"error": ...} — e.g. invalid query combination, dataset not found, or recommendations backend unable to produce suggestions for the given paperId.

Common situations: Calling recommendations for a paper with no embedding (obscure/new papers), malformed CorpusId, or Semantic Scholar returning structured API errors while still sending a 2xx status.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/988fd3877b1b50e4. Report an issue: GitHub.