Hmbown/CodeWhale · error · Error

CF_ACCOUNT_ID and CF_API_TOKEN are required

Error message

CF_ACCOUNT_ID and CF_API_TOKEN are required

What it means

main() requires Cloudflare credentials before issuing any D1 queries. It reads CF_ACCOUNT_ID and CF_API_TOKEN from the environment, trims them, and throws if either is missing or empty, because the script cannot authenticate to the Cloudflare API without both.

Solutions

  1. Export both variables before running: CF_ACCOUNT_ID=... CF_API_TOKEN=... node script.
  2. Add them to your .env / CI secret store and ensure it is actually loaded.
  3. Check for typos and whitespace: `echo "[$CF_ACCOUNT_ID]"` should show non-empty content.
  4. Use a Cloudflare API token scoped to D1 read for the correct account.

Example fix

// before
node telemetry-ingest/scripts/report-active-installs.mjs --days 30
// after
CF_ACCOUNT_ID=abc123 CF_API_TOKEN=xxxx node telemetry-ingest/scripts/report-active-installs.mjs --days 30
Defensive patterns

Strategy: validation

Validate before calling

if (!process.env.CF_ACCOUNT_ID?.trim() || !process.env.CF_API_TOKEN?.trim()) { console.error("Set CF_ACCOUNT_ID and CF_API_TOKEN first"); process.exit(1); }

Try / catch

try { await main(); } catch (e) { if (e.message.includes("CF_ACCOUNT_ID")) { console.error("Missing Cloudflare credentials: export CF_ACCOUNT_ID and CF_API_TOKEN"); process.exitCode = 2; } else throw e; }

Prevention

When it happens

Trigger: Running `report-active-installs` without exporting CF_ACCOUNT_ID or CF_API_TOKEN, or with either set to whitespace-only or empty string.

Common situations: Forgetting to source an .env file; running under CI where secrets were not injected; typo in variable name (e.g. CLOUDFLARE_API_TOKEN); shell where `export` was omitted.

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


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/82deb051becac09d. Report an issue: GitHub.

Appendix: source

Thrown at telemetry-ingest/scripts/report-active-installs.mjs:220

    headers: {
      Authorization: `Bearer ${apiToken}`,
      "content-type": "text/plain; charset=utf-8",
    },
    body: sql,
  });
  if (!response.ok) {
    const body = (await response.text()).slice(0, 500);
    throw new Error(`Cloudflare SQL request failed (${response.status}): ${body}`);
  }
  return response.json();
}

export async function main(argv = process.argv.slice(2), env = process.env) {
  const { days, json } = parseArgs(argv);
  const accountId = env.CF_ACCOUNT_ID?.trim();
  const apiToken = env.CF_API_TOKEN?.trim();
  if (!accountId || !apiToken) {
    throw new Error("CF_ACCOUNT_ID and CF_API_TOKEN are required");
  }
  const rows = rowsFromResponse(
    await querySql({ accountId, apiToken, sql: activeInstallsSql(days) }),
  );
  const newestEvent = newestEventFromResponse(
    await querySql({ accountId, apiToken, sql: freshnessSql() }),
  );
  const now = new Date();
  if (json) {
    process.stdout.write(
      `${JSON.stringify(
        {
          metric: "observed_active_installs",
          timezone: "UTC",
          days,
          rows,
          trend: trendSummary(rows, days, now),
          freshness: {

View on GitHub (pinned to 433685b202)