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

  1. Read the appended response body in the error message — it usually names the exact problem (e.g. invalid query field)
  2. Validate the payload: each query must use OSV's expected schema (version + package name + ecosystem)
  3. Retry on 5xx with backoff; fix the payload on 4xx
  4. 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

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


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