koala73/worldmonitor · error · Error
exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS
Error message
exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN is required for --check and --apply
What it means
resolveToken reads CLOUDFLARE_API_TOKEN and CLOUDFLARE_ALL_ACCESS_TOKEN from the environment and requires exactly one to be set. When neither is set it throws this message (when both are set it throws a different 'not both' message). The token is required to authenticate --check and --apply runs against the Cloudflare API.
Solutions
- Export CLOUDFLARE_API_TOKEN (or CLOUDFLARE_ALL_ACCESS_TOKEN) with a valid scoped token before running.
- Load your credentials file via the repo's loadEnvFile() mechanism or source it in the shell.
- In CI, add the secret and expose it as the exact environment variable name.
- Verify with `echo ${CLOUDFLARE_API_TOKEN:+set}` that exactly one variable is present.
Example fix
// before node scripts/cloudflare-cache-rule.mjs --check // no token in env // after export CLOUDFLARE_API_TOKEN=cf_your_token node scripts/cloudflare-cache-rule.mjs --check
Defensive patterns
Strategy: validation
Validate before calling
const tokens = [process.env.CLOUDFLARE_API_TOKEN, process.env.CLOUDFLARE_ALL_ACCESS_TOKEN].filter(Boolean);
if (tokens.length !== 1) {
throw new Error('export exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN before running');
} Type guard
function hasCloudflareToken(env = process.env) {
return [env.CLOUDFLARE_API_TOKEN, env.CLOUDFLARE_ALL_ACCESS_TOKEN].filter(Boolean).length === 1;
} Try / catch
try {
const token = resolveToken(env);
} catch (e) {
if (e.message.includes('is required for --check and --apply')) {
console.error('Missing Cloudflare token. Set CLOUDFLARE_API_TOKEN (or CLOUDFLARE_ALL_ACCESS_TOKEN) in the environment or via loadEnvFile().');
process.exit(2);
}
throw e;
} Prevention
- Load the repo env file via loadEnvFile() before running Cloudflare scripts.
- Map CI secrets to the exact variable names expected.
- Never set both token variables at once — use only one per environment.
- Smoke-test token presence with a quick env echo in CI before the script runs.
When it happens
Trigger: Running the script with --check or --apply in an environment where both token variables are unset — e.g. a CI job without secrets, a shell that never sourced the env file, or calling resolveToken with a custom env object lacking the keys.
Common situations: Fresh clone where the local .env was never loaded, GitHub Actions secrets not mapped into env, renamed/typo'd variable (CLOUDFLARE_TOKEN), or switching machines.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- global fetch is unavailable — Node 18+ is required
- DNS ${recordType} lookup failed: HTTP ${response.status}
- Expected one enabled block rule named ${description}
- Use --plan, --check, or --apply
- Cloudflare rules changed after planning. Run --plan again be
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/1765e6583d9b3ffc.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/cloudflare-cache-rule.mjs:536
token,
fetchImpl,
});
if (zone?.name !== ZONE_NAME) {
throw new Error(
`CLOUDFLARE_ZONE_ID ${env.CLOUDFLARE_ZONE_ID} is zone "${zone?.name ?? 'unknown'}", not ${ZONE_NAME}`,
);
}
return zone.id;
}
const zones = await cloudflareRequest(`/zones?name=${encodeURIComponent(ZONE_NAME)}`, { token, fetchImpl });
const zone = zones?.[0];
if (!zone) throw new Error(`no Cloudflare zone named ${ZONE_NAME} is visible to this token`);
return zone.id;
}
export function resolveToken(env = process.env) {
const tokens = [env.CLOUDFLARE_API_TOKEN, env.CLOUDFLARE_ALL_ACCESS_TOKEN].filter(Boolean);
if (tokens.length !== 1) {
throw new Error(
tokens.length
? 'set exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN, not both'
: 'exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN is required for --check and --apply',
);
}
return tokens[0];
}
/**
* Whether a live rule carries a ref somebody chose, as opposed to Cloudflare's
* default. Cloudflare fills an unset `ref` with the rule's own id, and — learned
* from the live zone while landing #7747 — refuses to change it afterwards: a
* PATCH that sends a new `ref` for such a rule fails with error 20142, "expected
* the reference to be empty". A ref is only ever accepted at creation. So a rule
* adopted by description keeps its default ref for life, and a default ref is
* identity to adopt, never drift to repair.
*/View on GitHub (pinned to 7d06c8633d)