jackwener/OpenCLI · warning · EmptyResultError

npm registry returned 404 for ${url}.

Error message

npm registry returned 404 for ${url}.

What it means

npmFetch wraps the public npm registry HTTP API (registry.npmjs.org / api.npmjs.org) and converts non-success responses into typed errors. When the endpoint answers HTTP 404, the URL could not be resolved to any known resource, so npmFetch throws EmptyResultError to signal 'nothing found' rather than a hard failure. Callers (like the body wrapper) use this to distinguish missing packages from genuine network or server errors.

Source

Thrown at clis/npm/utils.js:57

    if (n > maxValue) {
        throw new ArgumentError(`npm ${label} must be <= ${maxValue}`);
    }
    return n;
}

export async function npmFetch(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 ?? err}`,
            'Check that registry.npmjs.org / api.npmjs.org are reachable from this network.',
        );
    }
    if (resp.status === 404) {
        throw new EmptyResultError(label, `npm registry returned 404 for ${url}.`);
    }
    if (resp.status === 429) {
        throw new CommandExecutionError(
            `${label} returned HTTP 429 (rate limited)`,
            'npm throttles unauthenticated bursts; wait a few seconds 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 malformed JSON: ${err?.message ?? err}`);
    }
    return body;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the package name spelling with `npm view <name>` or on npmjs.com before retrying
  2. Check the exact URL being fetched; for scoped packages ensure the name is URL-encoded correctly (e.g. @babel%2fcore)
  3. If the package was unpublished or renamed, update to the correct/current name
  4. Handle EmptyResultError distinctly in calling code so 'not found' is reported as an empty result, not a crash

Example fix

// before
const data = await npmFetch(`${NPM_REGISTRY}/${encodeURIComponent(name)}`, 'npm package');
// after
try {
  const data = await npmFetch(`${NPM_REGISTRY}/${encodeURIComponent(name)}`, 'npm package');
} catch (err) {
  if (err instanceof EmptyResultError) {
    console.error(`Package "${name}" was not found on the npm registry.`);
    return null;
  }
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidNpmName(name) {
  const s = String(name ?? '').trim();
  return s.length > 0 && s.length <= 214 &&
    /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/i.test(s);
}
if (!isValidNpmName(pkg)) throw new Error(`Invalid npm package name: ${pkg}`);

Type guard

function isEmptyResultError(err) {
  return err instanceof Error && err.name === 'EmptyResultError';
}

Try / catch

try {
  const data = await npmFetch(`${NPM_REGISTRY}/${encodeURIComponent(pkg)}`, 'npm package');
  return data;
} catch (err) {
  if (err instanceof EmptyResultError || isEmptyResultError(err)) {
    return null; // package not found — treat as empty result
  }
  throw err;
}

Prevention

When it happens

Trigger: Any npmFetch call whose URL resolves to HTTP 404: fetching metadata for a package name that does not exist on the registry, a misspelled or renamed package, a scoped package without correct URL-encoding (e.g. '@scope/name' not encoded as @scope%2fname), or a deleted/unpublished package.

Common situations: Typos in a package name passed by a user ('reactt' instead of 'react'); querying a private-scope package on the public registry where it was never published; packages removed by npm for policy violations; stale scripts referencing packages that were renamed or deprecated.

Related errors


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