jackwener/OpenCLI · warning · EmptyResultError

OSV.dev returned no record for "${id}".

Error message

OSV.dev returned no record for "${id}".

What it means

The OSV vulnerability endpoint returned a 200 response whose body was empty or lacked an `id` field, so no usable record exists even though HTTP said OK. Thrown as EmptyResultError by the `vuln` command after osvGet succeeded.

Source

Thrown at clis/osv/vulnerability.js:29

    site: 'osv',
    name: 'vulnerability',
    access: 'read',
    description: 'Single OSV.dev vulnerability detail (severity, affected packages, CVE/GHSA aliases)',
    domain: 'osv.dev',
    strategy: Strategy.PUBLIC,
    browser: false,
    args: [
        { name: 'id', positional: true, type: 'string', required: true, help: 'OSV vulnerability id (e.g. "GHSA-29mw-wpgm-hmr9", "CVE-2020-28500")' },
    ],
    columns: [
        'id', 'summary', 'severity', 'aliases', 'published', 'modified',
        'affectedPackages', 'cwes', 'referenceCount', 'url',
    ],
    func: async (args) => {
        const id = requireVulnId(args.id);
        const vuln = await osvGet(`${OSV_BASE}/v1/vulns/${encodeURIComponent(id)}`, `osv vulnerability ${id}`);
        if (!vuln || !vuln.id) {
            throw new EmptyResultError('osv vulnerability', `OSV.dev returned no record for "${id}".`);
        }
        const affected = Array.isArray(vuln.affected) ? vuln.affected : [];
        const pkgPairs = [];
        for (const a of affected) {
            const eco = a?.package?.ecosystem;
            const name = a?.package?.name;
            if (eco && name) pkgPairs.push(`${eco}:${name}`);
        }
        const aliases = Array.isArray(vuln.aliases) ? vuln.aliases.filter(Boolean) : [];
        const cwes = Array.isArray(vuln?.database_specific?.cwe_ids) ? vuln.database_specific.cwe_ids : [];
        const refs = Array.isArray(vuln.references) ? vuln.references : [];
        return [{
            id: String(vuln.id),
            summary: String(vuln.summary ?? '').trim(),
            severity: severityLabel(vuln),
            aliases: aliases.join(', '),
            published: trimDate(vuln.published),
            modified: trimDate(vuln.modified),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Confirm the ID resolves on https://osv.dev/vulnerability/<id> in a browser
  2. Try the alias ID (e.g. GHSA form of a CVE) — OSV sometimes serves records under the canonical ID only
  3. Handle EmptyResultError gracefully and fall back to another advisory source (NVD, GitHub Advisory DB)
  4. Check whether a proxy is corrupting the response body (200 with non-JSON content)

Example fix

// before
const v = await osvGet(`${OSV_BASE}/v1/vulns/${id}`, label); // may throw EmptyResultError
// after
try { return await fetchVuln(id); }
catch (e) {
  if (e instanceof EmptyResultError) return fetchFromNvd(id);
  throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

if (!id || typeof id !== 'string' || !/^[A-Za-z]+-[A-Za-z0-9.-]+$/.test(id)) throw new Error(`Invalid vulnerability id: ${id}`);

Type guard

function isOsvVuln(v) { return v != null && typeof v === 'object' && typeof v.id === 'string' && v.id.length > 0; }

Try / catch

try {
  const rec = await vuln(id);
  return rec;
} catch (e) {
  if (/no record/i.test(e.message)) return nvdLookup(id) ?? ghsaLookup(id) ?? null;
  throw e;
}

Prevention

When it happens

Trigger: `vuln` called osvGet on `/v1/vulns/<id>`; requireVulnId passed but the parsed JSON was null/empty or missing `id` — e.g. the ID exists as an alias only, or OSV returned an empty/degenerate document.

Common situations: Querying an ID that OSV knows only as an alias of another record; a withdrawn advisory served with an empty body; an intermediary (proxy/cache) returning 200 with an empty or HTML body instead of JSON.

Related errors


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