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() normalizes a Cloudflare D1 SQL API response to an array of row objects: it accepts either a raw array or an object with a `data` array. If neither shape holds an array, it throws, because every downstream row-mapping would crash on a non-array.

Solutions

  1. Log the full payload to inspect the actual response shape (JSON.stringify(payload, null, 2)).
  2. If the Cloudflare envelope is `{results: [...]}` or `{result: {results: [...]}}`, update dataRows to read the correct field.
  3. Check that the request succeeded (response.ok) and authentication is valid before parsing; an error body often lacks `data`.
  4. If callers may pass an already-array payload, ensure they are not double-wrapping or passing `{data: {…}}` (non-array data).

Example fix

// before
const rows = Array.isArray(payload) ? payload : payload?.data;
// after
const rows = Array.isArray(payload) ? payload : payload?.data ?? payload?.result?.results;
Defensive patterns

Strategy: type-guard

Validate before calling

if (!Array.isArray(payload) && !Array.isArray(payload?.data)) console.error("unexpected D1 payload:", JSON.stringify(payload));

Type guard

function hasRows(p) { return Array.isArray(p) || Array.isArray(p?.data); }

Try / catch

try { const rows = rowsFromResponse(res); } catch (e) { if (e.message.includes("data array")) { console.error(JSON.stringify(res)); } throw e; }

Prevention

When it happens

Trigger: Calling rowsFromResponse()/dataRows() with a payload that is neither an array nor an object whose `data` field is an array — e.g. an unexpected Cloudflare API envelope, an error object returned as JSON, or null/undefined from a failed fetch.

Common situations: The D1 API changed its response envelope (e.g. results nested under `result.results` instead of `data`); a proxy or auth failure returned a JSON error body; the script was pointed at a mock/stub with a different shape.

Related errors


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

Appendix: 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 433685b202)