jackwener/OpenCLI · error · CommandExecutionError
${label} returned HTTP ${resp.status}.
Error message
${label} returned HTTP ${resp.status}. What it means
For any HTTP status that is not 404 or 429 and not ok, openfdaFetch throws this CommandExecutionError reporting the raw status code. It is the catch-all for server-side or authorization problems at api.fda.gov that are neither 'no matches' nor throttling. The label names the originating command.
Source
Thrown at clis/openfda/utils.js:41
return n;
}
export async function openfdaFetch(url, label) {
let resp;
try {
resp = await fetch(url, { headers: { 'User-Agent': UA, accept: 'application/json' } });
} catch (err) {
throw new CommandExecutionError(`${label} request failed: ${err.message}`);
}
if (resp.status === 404) {
// openFDA returns 404 for "no matches" instead of an empty results array.
throw new EmptyResultError(label, `${label} returned 404 (no matches).`);
}
if (resp.status === 429) {
throw new CommandExecutionError(`${label} rate-limited (HTTP 429); back off 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 non-JSON body: ${err.message}`);
}
return body;
}
// openFDA returns most string fields as `[string]` arrays — collapse to first
// element. Preserves `null` (not coerced to empty string) when the slot is
// missing entirely.
export function firstOrNull(arr) {
if (!Array.isArray(arr) || !arr.length) return null;
const v = arr[0];
if (typeof v !== 'string') return v ?? null;
const trimmed = v.trim();View on GitHub (pinned to 49907e53dc)
Solutions
- Read the status: 5xx means retry later with backoff; 401/403 means fix the API key; 400 means fix the query syntax.
- Check the openFDA status page / open.fda.gov to see if the API is degraded.
- Validate and simplify the search query (fewer clauses, proper +AND+ / +OR+ encoding).
- Include any configured API key correctly in the request and confirm it is still valid.
Example fix
// before
await openfdaFetch(`${OPENFDA_BASE}/drug/label.json?search=${rawQuery}`, 'openfda drug-label'); // 500 risk
// after
try {
await openfdaFetch(`${OPENFDA_BASE}/drug/label.json?search=${encodeURIComponent(rawQuery)}`, 'openfda drug-label');
} catch (e) {
await new Promise(r => setTimeout(r, 5000)); // retry on transient 5xx
return openfdaFetch(url, 'openfda drug-label');
} Defensive patterns
Strategy: try-catch
Validate before calling
function buildSearchQuery(clauses) {
if (!Array.isArray(clauses) || clauses.length === 0) throw new Error('at least one search clause required');
return clauses.map(encodeURIComponent).join('+AND+');
} Type guard
function isServerError(e) {
const m = e?.message?.match(/returned HTTP (\d{3})\./);
return m != null && Number(m[1]) >= 500;
} Try / catch
try {
const body = await openfdaFetch(url, label);
} catch (e) {
const m = e.message.match(/returned HTTP (\d{3})\./);
const code = m && Number(m[1]);
if (code >= 500) { /* backoff + retry */ }
else if (code === 401 || code === 403) { /* fix API key */ }
else if (code === 400) { /* fix query syntax */ }
else throw e;
} Prevention
- Retry 5xx with exponential backoff; they are usually transient.
- Validate API keys before deployment; 401/403 means bad key.
- Keep queries simple and correctly encoded to avoid 400s.
- Monitor the openFDA status page for degradation windows.
When it happens
Trigger: HTTP 500/502/503 when openFDA is down or a backend error occurs; HTTP 401/403 when an invalid API key is supplied or traffic is blocked; HTTP 400 from a malformed query that slips past client validation.
Common situations: openFDA maintenance windows returning 503; an expired or mistyped API key yielding 403; an over-complex search string the API rejects with 400; a load balancer 502 during traffic spikes.
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
- coingecko derivatives returned HTTP ${resp.status}
- ${label} returned HTTP ${resp.status}
- Detached HEAD — checkout a branch first
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
- archive search failed: HTTP ${resp.status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/27e4712e004317d2.
Report an issue: GitHub.