koala73/worldmonitor · error · Error
[backfillCanary250] unexpected Resend response shape: ${JSON
Error message
[backfillCanary250] unexpected Resend response shape: ${JSON.stringify(json).slice(0, 200)} What it means
Thrown by backfillCanary250 when the Resend response parses as JSON but does not have the expected shape — specifically json is falsy or json.data is not an array. This guards against silent schema drift where Resend changes its API response format, returning a 200 but with a different structure that would break the pagination/stamping loop.
Source
Thrown at convex/broadcast/backfillCanaryWaveStamps.ts:178
const res = await fetch(url.toString(), {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
"User-Agent": USER_AGENT,
},
});
if (!res.ok) {
const body = await res.text().catch(() => "<no body>");
throw new Error(
`[backfillCanary250] Resend list-contacts ${res.status}: ${body}`,
);
}
const json = (await res.json()) as ResendListContactsResponse;
if (!json || !Array.isArray(json.data)) {
throw new Error(
`[backfillCanary250] unexpected Resend response shape: ${JSON.stringify(json).slice(0, 200)}`,
);
}
for (const contact of json.data) {
stats.fetched++;
const normalizedEmail = (contact.email ?? "").trim().toLowerCase();
if (!normalizedEmail) {
stats.failed++;
continue;
}
try {
const out = await ctx.runMutation(
internal.broadcast.backfillCanaryWaveStamps
._stampWaveByNormalizedEmail,
{
normalizedEmail,
waveLabel: CANARY_WAVE_LABEL,View on GitHub (pinned to ffec79ac33)
Solutions
- Inspect the JSON fragment in the error message to see what Resend actually returned.
- Check Resend's API changelog for response-shape changes and update the ResendListContactsResponse type/parsing accordingly.
- If a proxy is interfering, route the request outside the proxy or whitelist the Resend domain.
- Log the full response once to confirm whether it's a transient anomaly or a permanent schema change.
Example fix
// before
const json = (await res.json()) as ResendListContactsResponse;
if (!json || !Array.isArray(json.data)) throw new Error("unexpected shape");
// after — log full body for diagnosis, then adapt parser
const raw = await res.text();
console.log("[backfill] raw Resend body:", raw.slice(0, 500));
const json = JSON.parse(raw);
const contacts = Array.isArray(json) ? json : json.data;
if (!Array.isArray(contacts)) throw new Error("unsupported shape"); Defensive patterns
Strategy: try-catch
Validate before calling
// Validate shape after parsing
const json = await res.json();
if (!json || !Array.isArray(json.data)) {
throw new Error("Resend response schema drifted — investigate before continuing");
} Type guard
function isResendListContactsResponse(json: unknown): json is { data: unknown[] } {
return !!json && typeof json === "object" && Array.isArray((json as any).data);
} Try / catch
try {
await backfillCanary250(ctx, {});
} catch (e) {
if (e.message.includes("unexpected Resend response shape")) {
// log full body, check Resend changelog, then decide
console.error(e.message);
} else throw e;
} Prevention
- Pin/monitor the Resend API version in use.
- Log the raw response body when shape drift is suspected.
- Update the ResendListContactsResponse type when Resend changes the envelope.
When it happens
Trigger: Resend returns a 200 OK but with a body where `data` is missing, is an object instead of an array, or the response is an error envelope that still returns 200; Resend ships a breaking API change; an unexpected proxy/CDN injects a non-JSON body that happened to parse.
Common situations: Resend API version bump changed the response envelope; a man-in-the-middle (corporate proxy) returned an HTML interstitial that parsed as partial JSON; Resend returned a top-level error object instead of a data array.
Related errors
- [backfillCanary250] RESEND_API_KEY not set — run with the sa
- [backfillCanary250] Resend list-contacts ${res.status}: ${bo
- [assignAndExportWave] waveLabel "${waveLabel}" already has s
- [assignAndExportWave] pool empty — all registrations are sup
- [backfillCanary250] CANARY_SENT_AT_MS failed Date.parse — ch
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/b5e3a90f1f73cd6e.
Report an issue: GitHub.