jackwener/OpenCLI · error · EmptyResultError
OpenAlex returned 404 for ${url}.
Error message
OpenAlex returned 404 for ${url}. What it means
openalexFetch maps an HTTP 404 from api.openalex.org to an EmptyResultError with the full request URL in the message. For the OpenAlex API, 404 means the requested entity path does not exist — typically an unrecognized or non-existent work ID/DOI. It is typed as EmptyResultError (not a transport failure) so callers can treat it like 'nothing found'.
Source
Thrown at clis/openalex/utils.js:93
throw new ArgumentError(
`openalex work id "${value}" is not recognised`,
'Use a Work id ("W2741809807"), a DOI ("10.7717/peerj.4375"), or a full openalex.org / doi.org URL.',
);
}
export async function openalexFetch(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 api.openalex.org is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `OpenAlex returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'OpenAlex throttles unauthenticated traffic; wait a few seconds and retry, or set OPENALEX_MAILTO.',
);
}
if (!resp.ok) {
let detail = '';
try {
const text = await resp.text();
const match = text.match(/"message"\s*:\s*"([^"]+)"/);
if (match) detail = ` (${match[1]})`;
}
catch { /* ignore */ }
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}${detail}`);
}
let body;View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the W-id/DOI exists by opening https://openalex.org/<id> or https://doi.org/<doi> in a browser
- Re-lookup the identifier via the openalex search command and use the returned id
- Check the ref wasn't mangled (truncated digits, wrong DOI suffix)
- If the DOI is correct but unindexed, the work may not be in OpenAlex — use an alternate source
Example fix
// before
await work('W9999999999'); // nonexistent
// after
const [hit] = await search('attention is all you need');
if (hit) await work(hit.id); Defensive patterns
Strategy: try-catch
Validate before calling
function isPlausibleWorkId(v) {
return /^W\d{4,}$/.test(String(v).trim().toUpperCase());
}
function isPlausibleDoi(v) {
return /^10\.\S+$/.test(String(v).trim());
}
if (!isPlausibleWorkId(ref) && !isPlausibleDoi(ref)) {
throw new Error('ref must be a W-id or DOI before lookup');
} Try / catch
try {
const w = await work(ref);
} catch (e) {
if (e.name === 'EmptyResultError' && e.message.includes('404')) {
console.warn(`Work not found for ${ref}; skipping`);
return null;
}
throw e;
} Prevention
- Verify IDs on openalex.org before bulk processing
- Re-resolve uncertain identifiers via the search endpoint
- Handle EmptyResultError distinctly so one bad ID doesn't abort a batch
When it happens
Trigger: Calling a work lookup with a ref that resolves to a canonical path OpenAlex has no record of — e.g. a well-formed but wrong/nonexistent W-id or DOI — producing a 404 from /works/<id> or /works/doi:….
Common situations: Hallucinated or fabricated W-ids; typos in a DOI; a DOI that was never registered with Crossref/OpenAlex; using an ID from a different provider (Semantic Scholar, MAG) that doesn't exist in OpenAlex.
Related errors
- Chess.com returned 404 for ${url}
- crates.io returned 404 for ${url}.
- Flathub returned 404 for ${url}.
- hf paper
- Homebrew API returned 404 for ${url}.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/83e2854d52777ee1.
Report an issue: GitHub.