koala73/worldmonitor · error
global fetch is unavailable — Node 18+ is required
Error message
global fetch is unavailable — Node 18+ is required
What it means
cli/src/run.mjs resolves its HTTP client as io.fetch || globalThis.fetch. Node releases before 18 have no global fetch (undici landed in Node 18), so run() aborts with this error before attempting any request; the generic catch maps it to exit code 1. The repository standardizes on Node 24 via .nvmrc.
Source
Thrown at cli/src/run.mjs:76
const env = io.env || (typeof process !== 'undefined' ? process.env : {});
const stdout = io.stdout || ((s) => process.stdout.write(s));
const stderr = io.stderr || ((s) => process.stderr.write(s));
const parsed = parseArgs(argv);
const { command, options } = parsed;
if (options.version) {
stdout(`${VERSION}\n`);
return 0;
}
if (options.help || !command || command === 'help') {
stdout(`${HELP}\n`);
return 0;
}
try {
if (!fetchImpl) {
throw new Error('global fetch is unavailable — Node 18+ is required');
}
const config = resolveConfig(env);
const plan = planRequest(parsed, config);
if (plan.kind === 'list') {
const specUrl = plan.specUrl || DEFAULT_SPEC_URL;
const headers = { 'user-agent': USER_AGENT, accept: 'application/json' };
const apiKey = options.apiKey || config.apiKey;
if (apiKey) headers[API_KEY_HEADER] = apiKey;
const res = await withTimeout(options.timeout, (signal) =>
fetchImpl(specUrl, { headers, signal }),
);
const spec = parseBody(await res.text(), res.headers);
if (!res.ok) {
stderr(`${formatOutput(spec, options)}\n`);
if (res.status === 401) stderr(`${AUTH_HINT}\n`);
return 1;View on GitHub (pinned to eeab0a219f)
Solutions
- Check node --version and upgrade to Node 18+ — ideally Node 24 per the repo's .nvmrc (nvm use)
- In CI, switch the base image to node:20+ or node:24
- When embedding run() programmatically, inject a client: run(argv, { fetch: myFetch })
- If a polyfill is unavoidable in the short term, set globalThis.fetch = require('undici').fetch before importing the CLI
Example fix
# before $ node --version v16.20.2 $ worldmonitor tools # Error: global fetch is unavailable — Node 18+ is required # after $ nvm use # picks up .nvmrc (Node 24) v24.x.x $ worldmonitor tools
Defensive patterns
Strategy: validation
Validate before calling
// Fail fast with a clear message before any CLI work
if (typeof globalThis.fetch !== 'function') {
console.error('Node 18+ required (global fetch missing). Current:', process.version);
process.exit(1);
} Type guard
type FetchLike = typeof globalThis.fetch;
function hasGlobalFetch(): fetch is FetchLike {
return typeof globalThis.fetch === 'function';
} Prevention
- Run `node --version` in shell profiles/CI before invoking the CLI
- Use the repository's .nvmrc (Node 24) in dev and CI
- When embedding run(), always inject io.fetch so tests and old runtimes stay hermetic
When it happens
Trigger: Executing the CLI under Node 16/14/10 (system node, stale nvm alias, CI image, Docker base); embedding run() without injecting io.fetch; exotic runtimes that lack a global fetch implementation.
Common situations: Dev machine defaulting to an old LTS via nvm; CI base image (node:16) never updated; tool managers shimming an old Node; calling run() from a test harness that forgets the fetch injection.
Related errors
- --args must be valid JSON: ${err.message}
- `get` needs an API path, e.g. `worldmonitor get /api/health`
- `call` needs a tool name, e.g. `worldmonitor call get_countr
- `${command}` needs <${a.name}>. Usage: worldmonitor ${comman
- Unknown command: ${command || '(none)'}. Run `worldmonitor -
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/4b512a8a9a40f972.
Report an issue: GitHub.