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
- Log the full payload to inspect the actual response shape (JSON.stringify(payload, null, 2)).
- If the Cloudflare envelope is `{results: [...]}` or `{result: {results: [...]}}`, update dataRows to read the correct field.
- Check that the request succeeded (response.ok) and authentication is valid before parsing; an error body often lacks `data`.
- 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
- Check response.ok before parsing JSON.
- Inspect the Cloudflare D1 API envelope for your API version before relying on `data`.
- Add a debug dump of the raw payload when the shape guard fails.
- Pin/monitor Cloudflare API version changes.
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
- Cloudflare SQL request failed
- Anthropic API error (HTTP )
- build platform HTTP client
- building bundle fetch client failed
- bundle fetch exceeded the five-redirect limit
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)