{"record":{"id":"1765e6583d9b3ffc","repo":"koala73/worldmonitor","slug":"exactly-one-of-cloudflare-api-token-or-cloudflare-all-access","errorCode":null,"errorMessage":"exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN is required for --check and --apply","messagePattern":"exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN is required for --check and --apply","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/cloudflare-cache-rule.mjs","lineNumber":536,"sourceCode":"      token,\n      fetchImpl,\n    });\n    if (zone?.name !== ZONE_NAME) {\n      throw new Error(\n        `CLOUDFLARE_ZONE_ID ${env.CLOUDFLARE_ZONE_ID} is zone \"${zone?.name ?? 'unknown'}\", not ${ZONE_NAME}`,\n      );\n    }\n    return zone.id;\n  }\n  const zones = await cloudflareRequest(`/zones?name=${encodeURIComponent(ZONE_NAME)}`, { token, fetchImpl });\n  const zone = zones?.[0];\n  if (!zone) throw new Error(`no Cloudflare zone named ${ZONE_NAME} is visible to this token`);\n  return zone.id;\n}\n\nexport function resolveToken(env = process.env) {\n  const tokens = [env.CLOUDFLARE_API_TOKEN, env.CLOUDFLARE_ALL_ACCESS_TOKEN].filter(Boolean);\n  if (tokens.length !== 1) {\n    throw new Error(\n      tokens.length\n        ? 'set exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN, not both'\n        : 'exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN is required for --check and --apply',\n    );\n  }\n  return tokens[0];\n}\n\n/**\n * Whether a live rule carries a ref somebody chose, as opposed to Cloudflare's\n * default. Cloudflare fills an unset `ref` with the rule's own id, and — learned\n * from the live zone while landing #7747 — refuses to change it afterwards: a\n * PATCH that sends a new `ref` for such a rule fails with error 20142, \"expected\n * the reference to be empty\". A ref is only ever accepted at creation. So a rule\n * adopted by description keeps its default ref for life, and a default ref is\n * identity to adopt, never drift to repair.\n */","sourceCodeStart":518,"sourceCodeEnd":554,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/cloudflare-cache-rule.mjs#L518-L554","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnode scripts/cloudflare-cache-rule.mjs --check   // no token in env\n// after\nexport CLOUDFLARE_API_TOKEN=cf_your_token\nnode scripts/cloudflare-cache-rule.mjs --check","handlingStrategy":"validation","validationCode":"const tokens = [process.env.CLOUDFLARE_API_TOKEN, process.env.CLOUDFLARE_ALL_ACCESS_TOKEN].filter(Boolean);\nif (tokens.length !== 1) {\n  throw new Error('export exactly one of CLOUDFLARE_API_TOKEN or CLOUDFLARE_ALL_ACCESS_TOKEN before running');\n}","typeGuard":"function hasCloudflareToken(env = process.env) {\n  return [env.CLOUDFLARE_API_TOKEN, env.CLOUDFLARE_ALL_ACCESS_TOKEN].filter(Boolean).length === 1;\n}","tryCatchPattern":"try {\n  const token = resolveToken(env);\n} catch (e) {\n  if (e.message.includes('is required for --check and --apply')) {\n    console.error('Missing Cloudflare token. Set CLOUDFLARE_API_TOKEN (or CLOUDFLARE_ALL_ACCESS_TOKEN) in the environment or via loadEnvFile().');\n    process.exit(2);\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["cloudflare","environment","credentials"],"backgroundTag":"missing-env-var","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}