jackwener/OpenCLI · info · EmptyResultError

${label} returned 404 (no matches).

Error message

${label} returned 404 (no matches).

What it means

openFDA signals 'no matches found' by returning HTTP 404 rather than an empty results array. openfdaFetch translates that 404 into an EmptyResultError with this message so callers can treat it as a normal empty outcome instead of a transport error. The label names the originating openfda command.

Source

Thrown at clis/openfda/utils.js:35

export function requireBoundedInt(value, def, max, name = 'limit') {
    const n = value == null || value === '' ? def : Number(value);
    if (!Number.isInteger(n) || n < 1 || n > max) {
        throw new ArgumentError(`--${name} must be an integer between 1 and ${max}`);
    }
    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

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Broaden or correct the search term / filters and retry.
  2. Validate terms against openFDA's own search UI (open.fda.gov) before scripting them.
  3. Catch EmptyResultError in calling code and render 'no results' instead of failing.
  4. If 404 appears for a URL that should match, verify the endpoint path and query encoding (use +AND+ between clauses).

Example fix

// before
const rows = await fetchFoodRecalls({ q: 'Xyzzysnacks' }); // throws EmptyResultError
// after
try {
  const rows = await fetchFoodRecalls({ q: 'Xyzzysnacks' });
} catch (e) {
  if (e instanceof EmptyResultError) return []; // treat as empty
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function validateRecallQuery({ q }) {
  if (q != null && q.trim().length < 2) throw new Error('search term too short');
  return true;
}

Type guard

function isEmptyResult(e) {
  return e instanceof Error && e.name === 'EmptyResultError';
}

Try / catch

try {
  const rows = await fetchFoodRecalls(filter);
} catch (e) {
  if (e instanceof EmptyResultError || /404 \(no matches\)/.test(e.message)) {
    return []; // openFDA 404 == zero matches, not a failure
  }
  throw e;
}

Prevention

When it happens

Trigger: Any openfda query whose search term(s) match zero records — misspelled drug name, recall filters that never co-occur, an NDC/product string absent from the database. openfdaFetch converts the 404 status before the general !resp.ok branch runs.

Common situations: Searching a drug that only exists under another spelling; querying enforcement records for a state/date combo with no recalls; automations that assume every query has results and crash on the empty case.

Related errors


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