koala73/worldmonitor · error · Error
[assignAndExportWave] waveLabel "${waveLabel}" already has s
Error message
[assignAndExportWave] waveLabel "${waveLabel}" already has stamped rows — pick a unique label, or use the Resend dashboard to inspect/clean up the prior wave's segment first. What it means
Thrown by assignAndExportWave when _hasWaveLabel returns true — i.e. registrations already exist stamped with the given waveLabel. This prevents overlapping waves that would double-send to the same recipients. The operator must use a unique label or clean up the prior wave's Resend segment first.
Source
Thrown at convex/broadcast/audienceWaveExport.ts:299
}
if (!Number.isFinite(count) || count <= 0) {
throw new Error(
`[assignAndExportWave] count must be a positive integer; got ${count}`,
);
}
if (waveLabel.length === 0 || waveLabel.length > 64) {
throw new Error(
"[assignAndExportWave] waveLabel must be 1-64 chars",
);
}
// Step 1: refuse to overlap with an existing wave.
const exists = await ctx.runQuery(
internal.broadcast.audienceWaveExport._hasWaveLabel,
{ waveLabel },
);
if (exists) {
throw new Error(
`[assignAndExportWave] waveLabel "${waveLabel}" already has stamped rows — pick a unique label, or use the Resend dashboard to inspect/clean up the prior wave's segment first.`,
);
}
// Step 2: stream registrations, dedup, reservoir-sample N.
const [suppressed, paid] = await Promise.all([
ctx.runQuery(
internal.broadcast.audienceWaveExport._getSuppressedEmails,
{},
),
ctx.runQuery(internal.broadcast.audienceWaveExport._getPaidEmails, {}),
]);
const suppressedSet = new Set(suppressed);
const paidSet = new Set(paid);
const reservoir = new Reservoir<string>(count);
let cursor: string | null = null;
while (true) {View on GitHub (pinned to ffec79ac33)
Solutions
- Use a unique waveLabel for each assignAndExportWave invocation (e.g. append a counter or timestamp).
- Inspect the prior wave's stamped rows and Resend segment via the Resend dashboard before reusing a label.
- If the prior wave is genuinely superseded, pick a fresh label rather than trying to reuse it.
Example fix
// before
await assignAndExportWave(ctx, { waveLabel: "wave-7", count: 500 }); // already has stamped rows
// after — unique label per run
await assignAndExportWave(ctx, { waveLabel: `wave-7-${Date.now()}`, count: 500 }); Defensive patterns
Strategy: validation
Validate before calling
const exists = await ctx.runQuery(internal.broadcast.audienceWaveExport._hasWaveLabel, { waveLabel });
if (exists) throw new Error(`waveLabel ${waveLabel} already used — pick a new one`);
await assignAndExportWave(ctx, { waveLabel, count }); Try / catch
try {
await assignAndExportWave(ctx, { waveLabel, count });
} catch (e) {
if (e.message.includes("already has stamped rows")) {
waveLabel = `${baseLabel}-${Date.now()}`; // unique suffix
await assignAndExportWave(ctx, { waveLabel, count });
} else throw e;
} Prevention
- Always use a unique waveLabel (append counter or timestamp).
- Check _hasWaveLabel before calling assignAndExportWave.
- Coordinate label schemes across operators to avoid collisions.
When it happens
Trigger: Calling assignAndExportWave with a waveLabel that already appears in registrations.proLaunchWave (or wherever _hasWaveLabel checks); re-running a wave export with the same label after a partial or prior run; a label collision across manual and automated waves.
Common situations: Retrying a failed wave run with the same label instead of a new one; two operators using overlapping label schemes (e.g. both using '2024-01'); resuming an interrupted run without checking which label was already stamped.
Related errors
- [assignAndExportWave] pool empty — all registrations are sup
- [backfillCanary250] RESEND_API_KEY not set — run with the sa
- [backfillCanary250] Resend list-contacts ${res.status}: ${bo
- [backfillCanary250] unexpected Resend response shape: ${JSON
- [initRamp] ramp already configured (active=${existing.active
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/9c21acc9b4643dce.
Report an issue: GitHub.