jackwener/OpenCLI · error · CommandExecutionError
${label} returned HTTP ${resp.status}${text ? `: ${text.slic
Error message
${label} returned HTTP ${resp.status}${text ? `: ${text.slice(0, 200)}` : ''} What it means
osvPost received an unexpected non-ok HTTP status (not 404/429) from api.osv.dev. The error includes up to 200 characters of the response body to aid diagnosis — commonly a 4xx/5xx from the OSV API or an intermediary.
Source
Thrown at clis/osv/utils.js:143
headers: { 'user-agent': UA, accept: 'application/json', 'content-type': 'application/json' },
body: JSON.stringify(payload),
});
}
catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that api.osv.dev is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `OSV.dev returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(`${label} returned HTTP 429 (rate limited)`);
}
if (!resp.ok) {
const text = await resp.text().catch(() => '');
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}${text ? `: ${text.slice(0, 200)}` : ''}`);
}
return readJson(resp, label);
}
// Reduce OSV's `severity` array to a single human-readable label.
// Returns null when no severity is recorded; never invents a value.
export function severityLabel(vuln) {
const dbSpecific = vuln?.database_specific;
if (dbSpecific && typeof dbSpecific.severity === 'string' && dbSpecific.severity.trim()) {
return dbSpecific.severity.trim();
}
const arr = Array.isArray(vuln?.severity) ? vuln.severity : [];
for (const entry of arr) {
if (entry && typeof entry.score === 'string' && entry.score.trim()) {
return entry.score.trim();
}
}
return null;View on GitHub (pinned to 49907e53dc)
Solutions
- Read the appended response body in the error message — it usually names the exact problem (e.g. invalid query field)
- Validate the payload: each query must use OSV's expected schema (version + package name + ecosystem)
- Retry on 5xx with backoff; fix the payload on 4xx
- Bypass intermediaries by testing the identical POST with curl to isolate proxy vs API issues
Example fix
// before
await osvPost(url, { queries: [{ package: { name: pkg } }] }, label);
// after
await osvPost(url, { queries: [{ package: { name: pkg, ecosystem: 'npm' }, version: ver }] }, label); Defensive patterns
Strategy: try-catch
Validate before calling
const ecosystem = 'npm'; // must be an OSV-recognized ecosystem string
if (!['npm','PyPI','Packagist','Go','Maven','crates.io','RubyGems','NuGet'].includes(ecosystem)) throw new Error(`Unsupported ecosystem: ${ecosystem}`); Type guard
function isHttpError(err) { return err instanceof Error && /returned HTTP \d{3}/.test(err.message); } Try / catch
try {
return await osvBatch(payload);
} catch (e) {
if (isHttpError(e)) {
console.error('OSV rejected request:', e.message); // body excerpt appended by the library
if (/HTTP 5\d\d/.test(e.message)) return retryWithBackoff(() => osvBatch(payload));
}
throw e;
} Prevention
- Read the response-body excerpt included in the error message — it names the exact problem
- Validate query payloads against the OSV querybatch schema before sending
- Always include a valid ecosystem name in each package query
- Retry only 5xx statuses; fix payloads on 4xx
When it happens
Trigger: osvPost to a querybatch endpoint got a status like 400 (malformed query payload), 403, 500, 502 or 503; the response body text is appended to the message when readable.
Common situations: Sending a malformed JSON payload or unsupported ecosystem name in the batch query (400); OSV.dev outage (5xx); corporate proxy rejecting the request (403/502); TLS interception returning an HTML error page.
Related errors
- API_ERROR
- API_ERROR
- arXiv API HTTP ${resp.status}
- ${label} returned HTTP ${resp.status}
- HTTP ${result.httpStatus} from /api/user
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c790ccdc690d5217.
Report an issue: GitHub.