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

  1. 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.
  2. Confirm RESEND_API_KEY is valid and authorized for the Resend account owning the canary segment.
  3. Verify CANARY_SEGMENT_ID in the source matches an existing Resend segment.
  4. 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

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


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/d19e819ceb166c47. Report an issue: GitHub.