Hmbown/CodeWhale · error · Error

Cloudflare SQL response did not contain a data array

Error message

Cloudflare SQL response did not contain a data array

What it means

dataRows extracts the row array from a Cloudflare SQL API response: either the payload itself is an array, or payload.data must be one. If the shape does not match — an error object, a string, or null came back — it throws 'Cloudflare SQL response did not contain a data array'. rowsFromResponse and newestEventFromResponse both depend on this extraction.

Source

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

WHERE timestamp >= toStartOfDay(NOW()) - INTERVAL '${days - 1}' DAY
  AND blob1 = 'session_start'
GROUP BY day
ORDER BY day DESC
FORMAT JSON`;
}

/** Newest ingested event of any kind — how stale the dataset is. */
export function freshnessSql() {
  return `SELECT
  max(timestamp) AS newest_event
FROM codewhale_telemetry
FORMAT JSON`;
}

function dataRows(payload) {
  const rows = Array.isArray(payload) ? payload : payload?.data;
  if (!Array.isArray(rows)) {
    throw new Error("Cloudflare SQL response did not contain a data array");
  }
  return rows;
}

export function rowsFromResponse(payload) {
  return dataRows(payload).map((row) => ({
    day: String(row.day),
    active_installs: Number(row.active_installs),
    sessions_started: Number(row.sessions_started),
  }));
}

/** `null` when the dataset has no rows at all. */
export function newestEventFromResponse(payload) {
  const raw = dataRows(payload)[0]?.newest_event;
  if (raw === undefined || raw === null || String(raw).startsWith("0000")) {
    return null;
  }

View on GitHub (pinned to 8880682c63)

Solutions

  1. Log the raw payload before parsing to see the actual shape that arrived
  2. Re-issue the query via the Cloudflare dashboard/API and compare response shapes
  3. If the schema changed, update dataRows to read the new field while keeping the Array.isArray guard

Example fix

// before
const rows = payload?.data;
// after
const rows = Array.isArray(payload) ? payload : payload?.data;
if (!Array.isArray(rows)) {
  throw new Error('Cloudflare SQL response did not contain a data array');
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!isSqlRowsPayload(payload)) {
  console.error('unexpected Cloudflare SQL payload shape:', JSON.stringify(payload).slice(0, 200));
  process.exit(2);
}

Type guard

function isSqlRowsPayload(payload) {
  return Array.isArray(payload) || Array.isArray(payload?.data);
}

Try / catch

try {
  rowsFromResponse(payload);
} catch (error) {
  if (/did not contain a data array/.test(error.message)) {
    console.error('Cloudflare SQL payload changed — inspect raw response');
    process.exit(2);
  }
  throw error;
}

Prevention

When it happens

Trigger: The SQL endpoint returning HTTP 200 with a body lacking a data array (error/status object, wrapped payload, changed response schema); passing a parsed body from a different endpoint version.

Common situations: Cloudflare API evolution changing the envelope; a proxied or transformed response; empty responses on brand-new accounts with no telemetry rows.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/a534dd385727779c. Report an issue: GitHub.