{"record":{"id":"46c8011dc4a9d9a8","repo":"Hmbown/CodeWhale","slug":"cloudflare-sql-request-failed-response-status","errorCode":null,"errorMessage":"Cloudflare SQL request failed (${response.status}): ${body}","messagePattern":"Cloudflare SQL request failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"telemetry-ingest/scripts/report-active-installs.mjs","lineNumber":210,"sourceCode":"  lines.push(\"\", \"Caveats:\");\n  for (const caveat of COVERAGE_CAVEATS) {\n    lines.push(`  - ${caveat}`);\n  }\n  return lines.join(\"\\n\");\n}\n\nasync function querySql({ accountId, apiToken, sql, fetchImpl = fetch }) {\n  const response = await fetchImpl(SQL_ENDPOINT(accountId), {\n    method: \"POST\",\n    headers: {\n      Authorization: `Bearer ${apiToken}`,\n      \"content-type\": \"text/plain; charset=utf-8\",\n    },\n    body: sql,\n  });\n  if (!response.ok) {\n    const body = (await response.text()).slice(0, 500);\n    throw new Error(`Cloudflare SQL request failed (${response.status}): ${body}`);\n  }\n  return response.json();\n}\n\nexport async function main(argv = process.argv.slice(2), env = process.env) {\n  const { days, json } = parseArgs(argv);\n  const accountId = env.CF_ACCOUNT_ID?.trim();\n  const apiToken = env.CF_API_TOKEN?.trim();\n  if (!accountId || !apiToken) {\n    throw new Error(\"CF_ACCOUNT_ID and CF_API_TOKEN are required\");\n  }\n  const rows = rowsFromResponse(\n    await querySql({ accountId, apiToken, sql: activeInstallsSql(days) }),\n  );\n  const newestEvent = newestEventFromResponse(\n    await querySql({ accountId, apiToken, sql: freshnessSql() }),\n  );\n  const now = new Date();","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/telemetry-ingest/scripts/report-active-installs.mjs#L192-L228","documentation":"querySql POSTs the raw SQL text to SQL_ENDPOINT(accountId) with a Bearer CF_API_TOKEN; a non-ok response throws `Cloudflare SQL request failed (${response.status}): ${body}` including the first 500 chars of the body. The status plus embedded Cloudflare error body distinguishes auth, account, and query problems.","triggerScenarios":"400 for invalid SQL syntax; 401/403 for a token missing the required read scope or that was revoked; 404 for a wrong CF_ACCOUNT_ID; 429 rate limiting.","commonSituations":"Token created without the Analytics/SQL read permission; account id copied from a different Cloudflare account; hand-edited SQL breaking syntax.","solutions":["Read the embedded body first — Cloudflare error codes name the exact problem","Re-create CF_API_TOKEN with the required read scope and access to the right account","Verify CF_ACCOUNT_ID matches the account hosting the codewhale_telemetry dataset","On 429 or transient 5xx, retry with backoff instead of immediately re-running"],"exampleFix":"# before\nCF_ACCOUNT_ID=wrongaccount CF_API_TOKEN=noaccess node scripts/report-active-installs.mjs\n# after\nCF_ACCOUNT_ID=<id from dash> CF_API_TOKEN=<token with SQL read scope> node scripts/report-active-installs.mjs","handlingStrategy":"try-catch","validationCode":"if (!env.CF_ACCOUNT_ID?.trim() || !env.CF_API_TOKEN?.trim()) {\n  console.error('CF_ACCOUNT_ID and CF_API_TOKEN are required');\n  process.exit(2);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await querySql({ accountId, apiToken, sql });\n} catch (error) {\n  const status = Number(error.message.match(/failed \\((\\d+)\\)/)?.[1]);\n  if (status === 429 || status >= 500) { await delay(backoffMs); return querySql({ accountId, apiToken, sql }); }\n  throw error;\n}","preventionTips":["Create the API token with only the SQL/Analytics read scope it needs and record the scope in the secret's description","Smoke-test credentials with a trivial query before scheduling reports"],"tags":["network","api","auth","cloudflare","telemetry"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}