{"record":{"id":"7cd396a282baa137","repo":"koala73/worldmonitor","slug":"pickwaveaction-wavelabel-must-be-1-64-chars","errorCode":null,"errorMessage":"[pickWaveAction] waveLabel must be 1-64 chars","messagePattern":"\\[pickWaveAction\\] waveLabel must be 1-64 chars","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"convex/broadcast/waveRuns.ts","lineNumber":706,"sourceCode":"    // Filter contacts whose locale (from `users.localePrimary` or email-TLD\n    // heuristic fallback) is non-English. Filter runs INSIDE the registration\n    // pagination loop, BEFORE reservoir sampling — sampling-then-filtering\n    // would silently underfill (sample 1000, exclude 200, send 800 even\n    // though thousands of eligible English contacts existed elsewhere).\n    excludeNonEnglish: v.optional(v.boolean()),\n  },\n  handler: async (ctx, args): Promise<{ ok: boolean; reason?: string }> => {\n    const apiKey = process.env.RESEND_API_KEY;\n    if (!apiKey) {\n      throw new Error(\"[pickWaveAction] RESEND_API_KEY not set\");\n    }\n    if (!Number.isFinite(args.requestedCount) || args.requestedCount <= 0) {\n      throw new Error(\n        `[pickWaveAction] requestedCount must be a positive integer; got ${args.requestedCount}`,\n      );\n    }\n    if (args.waveLabel.length === 0 || args.waveLabel.length > 64) {\n      throw new Error(\"[pickWaveAction] waveLabel must be 1-64 chars\");\n    }\n    const batchSize = args.batchSize ?? DEFAULT_BATCH_SIZE;\n    const excludeNonEnglish = args.excludeNonEnglish === true;\n\n    // Step 1: claim lease + insert waveRuns row.\n    const claim: ClaimLeaseResult = await ctx.runMutation(\n      internal.broadcast.waveRuns._claimWaveRunLease,\n      {\n        waveLabel: args.waveLabel,\n        runId: args.runId,\n        requestedCount: args.requestedCount,\n        batchSize,\n      },\n    );\n    if (!claim.ok) {\n      throw new Error(\n        `[pickWaveAction] could not claim lease: ${claim.reason}` +\n        (claim.current ? ` (current: ${claim.current})` : \"\"),","sourceCodeStart":688,"sourceCodeEnd":724,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/convex/broadcast/waveRuns.ts#L688-L724","documentation":"Argument validation in pickWaveAction: waveLabel is empty or longer than 64 characters. The label becomes the waveRuns identifier and a Resend segment-name component, so it must be a non-empty bounded string.","triggerScenarios":"Thrown at convex/broadcast/waveRuns.ts:706 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Use the configured waveLabelPrefix plus tier label (e.g. 'pro-8'), which is well under 64 chars","Validate label length in the ramp runner before dispatching the pick action"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"eeab0a219fce0f02a00603b532dbae9041b934ac","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}