{"record":{"id":"9c21acc9b4643dce","repo":"koala73/worldmonitor","slug":"assignandexportwave-wavelabel-wavelabel-alr","errorCode":null,"errorMessage":"[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.","messagePattern":"\\[assignAndExportWave\\] waveLabel \"(.+?)\" already has stamped rows — pick a unique label, or use the Resend dashboard to inspect/clean up the prior wave's segment first\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"convex/broadcast/audienceWaveExport.ts","lineNumber":299,"sourceCode":"    }\n    if (!Number.isFinite(count) || count <= 0) {\n      throw new Error(\n        `[assignAndExportWave] count must be a positive integer; got ${count}`,\n      );\n    }\n    if (waveLabel.length === 0 || waveLabel.length > 64) {\n      throw new Error(\n        \"[assignAndExportWave] waveLabel must be 1-64 chars\",\n      );\n    }\n\n    // Step 1: refuse to overlap with an existing wave.\n    const exists = await ctx.runQuery(\n      internal.broadcast.audienceWaveExport._hasWaveLabel,\n      { waveLabel },\n    );\n    if (exists) {\n      throw new Error(\n        `[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.`,\n      );\n    }\n\n    // Step 2: stream registrations, dedup, reservoir-sample N.\n    const [suppressed, paid] = await Promise.all([\n      ctx.runQuery(\n        internal.broadcast.audienceWaveExport._getSuppressedEmails,\n        {},\n      ),\n      ctx.runQuery(internal.broadcast.audienceWaveExport._getPaidEmails, {}),\n    ]);\n    const suppressedSet = new Set(suppressed);\n    const paidSet = new Set(paid);\n\n    const reservoir = new Reservoir<string>(count);\n    let cursor: string | null = null;\n    while (true) {","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/koala73/worldmonitor/blob/ffec79ac339946fd2d24e85845da5755dcaa534b/convex/broadcast/audienceWaveExport.ts#L281-L317","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait assignAndExportWave(ctx, { waveLabel: \"wave-7\", count: 500 }); // already has stamped rows\n// after — unique label per run\nawait assignAndExportWave(ctx, { waveLabel: `wave-7-${Date.now()}`, count: 500 });","handlingStrategy":"validation","validationCode":"const exists = await ctx.runQuery(internal.broadcast.audienceWaveExport._hasWaveLabel, { waveLabel });\nif (exists) throw new Error(`waveLabel ${waveLabel} already used — pick a new one`);\nawait assignAndExportWave(ctx, { waveLabel, count });","typeGuard":null,"tryCatchPattern":"try {\n  await assignAndExportWave(ctx, { waveLabel, count });\n} catch (e) {\n  if (e.message.includes(\"already has stamped rows\")) {\n    waveLabel = `${baseLabel}-${Date.now()}`; // unique suffix\n    await assignAndExportWave(ctx, { waveLabel, count });\n  } else throw e;\n}","preventionTips":["Always use a unique waveLabel (append counter or timestamp).","Check _hasWaveLabel before calling assignAndExportWave.","Coordinate label schemes across operators to avoid collisions."],"tags":["convex","broadcast","resend","wave-export","uniqueness","idempotency"],"backgroundTag":null,"analyzedSha":"ffec79ac339946fd2d24e85845da5755dcaa534b","analyzedAt":"2026-08-12T11:24:56.012Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}