koala73/worldmonitor · warning · Error
[assignAndExportWave] pool empty — all registrations are sup
Error message
[assignAndExportWave] pool empty — all registrations are suppressed/paid/already-stamped. Nothing to send.
What it means
Thrown by assignAndExportWave when the reservoir picked zero eligible emails after streaming all registrations. Every candidate was filtered out because it was suppressed, paid, or already stamped with a proLaunchWave. This signals the waitlist is drained for this ramp tier and there is nothing to send.
Source
Thrown at convex/broadcast/audienceWaveExport.ts:350
{ cursor, numItems: REGISTRATIONS_PAGE_SIZE },
);
for (const row of page.page) {
const email = row.normalizedEmail;
if (!email || email.length === 0) continue;
if (suppressedSet.has(email)) continue;
if (paidSet.has(email)) continue;
if (row.proLaunchWave) continue;
reservoir.offer(email);
}
if (page.isDone) break;
cursor = page.continueCursor;
}
const picked = reservoir.values();
const poolSize = reservoir.totalSeen();
if (picked.length === 0) {
throw new Error(
`[assignAndExportWave] pool empty — all registrations are suppressed/paid/already-stamped. Nothing to send.`,
);
}
// Step 3: create the Resend segment FIRST so we never stamp a
// contact until we know it has a destination to land in. If
// segment creation fails, the picked rows are still unstamped and
// remain available for the next wave's pick — no data loss, no
// stranded contacts.
const segmentName = `pro-launch-${waveLabel}`;
const segmentId = await createSegment(apiKey, segmentName);
// Step 4: push picked contacts to the segment, then stamp ONLY on
// successful push outcomes (created / linkedExisting /
// alreadyInSegment). This ordering is load-bearing — see the
// file docstring's "Atomicity" section.
//
// - push succeeds → stamp Convex → contact won't be re-pickedView on GitHub (pinned to ffec79ac33)
Solutions
- Treat this as end-of-ramp — reduce or stop further wave scheduling for this audience.
- Inspect the suppression list and paid set sizes to confirm the pool is genuinely exhausted (not a misconfiguration).
- If suppression is unexpectedly large, audit the suppression source for an over-broad rule.
- Do not retry with the same parameters — the pool state will not change without new registrations.
Example fix
// before
await assignAndExportWave(ctx, { waveLabel: "wave-99", count: 500 }); // pool empty
// after — guard before calling; check remaining pool size
const remaining = await ctx.runQuery(internal.broadcast.audienceWaveExport._countEligible, {});
if (remaining === 0) {
console.log("Waitlist exhausted — ramp complete.");
return;
} Defensive patterns
Strategy: validation
Validate before calling
// Pre-check eligible pool size before exporting
const remaining = await ctx.runQuery(internal.broadcast.audienceWaveExport._countEligible, {});
if (remaining === 0) {
console.log("Waitlist exhausted — ramp complete.");
return;
}
await assignAndExportWave(ctx, { waveLabel, count }); Try / catch
try {
await assignAndExportWave(ctx, { waveLabel, count });
} catch (e) {
if (e.message.includes("pool empty")) {
// end of ramp — stop scheduling further waves
} else throw e;
} Prevention
- Monitor remaining eligible pool size as the ramp progresses.
- Treat pool-empty as end-of-ramp, not a transient retry.
- Audit the suppression list if the pool empties unexpectedly early.
When it happens
Trigger: All registrations are in the suppressed set, the paid set, or already have proLaunchWave set; the waitlist has been fully processed for prior waves; suppression list grew to cover the entire remaining pool.
Common situations: End of a launch ramp — all registrants already received their wave; an over-broad suppression rule filtered everyone; paid users dominate the small remaining pool; a prior wave stamped the last unstamped rows.
Related errors
- [assignAndExportWave] waveLabel "${waveLabel}" already has s
- [backfillCanary250] RESEND_API_KEY not set — run with the sa
- [backfillCanary250] Resend list-contacts ${res.status}: ${bo
- [backfillCanary250] unexpected Resend response shape: ${JSON
- [backfillCanary250] CANARY_SENT_AT_MS failed Date.parse — ch
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/85857d3f8df37644.
Report an issue: GitHub.