koala73/worldmonitor · error · Error
[backfillCanary250] Resend list-contacts ${res.status}: ${bo
Error message
[backfillCanary250] Resend list-contacts ${res.status}: ${body} What it means
Thrown by backfillCanary250 when the Resend GET /segments/{id}/contacts request returns a non-OK HTTP status. The error includes the status code and the response body (or '<no body>' if reading the body failed) so the operator can diagnose the upstream Resend failure. This wraps any 4xx/5xx from Resend into an actionable error.
Source
Thrown at convex/broadcast/backfillCanaryWaveStamps.ts:171
// documented inconsistently across Resend's docs pages — only
// the `/segments/{id}/contacts` route is canonical.
const url = new URL(
`${RESEND_API_BASE}/segments/${encodeURIComponent(CANARY_SEGMENT_ID)}/contacts`,
);
url.searchParams.set("limit", String(RESEND_PAGE_SIZE));
if (after) url.searchParams.set("after", after);
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;
}View on GitHub (pinned to ffec79ac33)
Solutions
- Check the HTTP status in the error message: 401/403 → rotate and redeploy RESEND_API_KEY; 404 → verify CANARY_SEGMENT_ID exists in Resend; 429 → back off and retry; 5xx → retry after Resend recovers.
- Confirm RESEND_API_KEY is valid and authorized for the Resend account owning the canary segment.
- Verify CANARY_SEGMENT_ID in the source matches an existing Resend segment.
- For rate limits, reduce RESEND_PAGE_SIZE or add delays between pages.
Example fix
// before
const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` }});
if (!res.ok) throw new Error(`...${res.status}...`); // 401 from expired key
// after — ensure key is current
// $ npx convex env set RESEND_API_KEY re_newvalue
// then re-run backfillCanary250 Defensive patterns
Strategy: retry
Validate before calling
if (!process.env.RESEND_API_KEY) throw new Error("RESEND_API_KEY missing");
// Preflight: verify segment exists with a HEAD/GET before paging
// (optional — reduces surprise failures) Try / catch
for (let attempt = 0; attempt < 3; attempt++) {
try {
await backfillCanary250(ctx, {});
break;
} catch (e) {
const status = /Resend list-contacts (\d+)/.exec(e.message)?.[1];
if (status === "429" || (status && +status >= 500) && attempt < 2) {
await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
continue;
}
throw e;
}
} Prevention
- Keep RESEND_API_KEY current; rotate before expiry.
- Verify CANARY_SEGMENT_ID exists in the Resend dashboard before backfill.
- For 429/5xx, retry with backoff; for 401/403/404, fix config first.
When it happens
Trigger: Resend returns 401 (invalid/expired API key), 403 (forbidden), 404 (segment id does not exist), 429 (rate limit), or 5xx (Resend outage); the CANARY_SEGMENT_ID points to a deleted segment; network/proxy interference altered the response.
Common situations: RESEND_API_KEY was revoked or rotated but not updated in Convex env; the canary segment was deleted in the Resend dashboard; hitting Resend's rate limit during a large backfill; transient Resend 5xx during the request window.
Related errors
- [backfillCanary250] RESEND_API_KEY not set — run with the sa
- [backfillCanary250] unexpected Resend response shape: ${JSON
- [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/d19e819ceb166c47.
Report an issue: GitHub.