{"record":{"id":"d2d913aa04fc2099","repo":"koala73/worldmonitor","slug":"pickwaveaction-could-not-claim-lease-claim-re","errorCode":null,"errorMessage":"[pickWaveAction] could not claim lease: ${claim.reason} (current: ${claim.current})","messagePattern":"\\[pickWaveAction\\] could not claim lease: (.+?) \\(current: (.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"convex/broadcast/waveRuns.ts","lineNumber":722,"sourceCode":"    }\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})` : \"\"),\n      );\n    }\n\n    try {\n      // Step 2: stream registrations + filter (per-page) + reservoir-sample.\n      const [suppressed, paid] = await Promise.all([\n        ctx.runQuery(internal.broadcast.waveRuns._getSuppressedEmails, {}),\n        ctx.runQuery(internal.broadcast.waveRuns._getPaidEmails, {}),\n      ]);\n      const suppressedSet = new Set(suppressed);\n      const paidSet = new Set(paid);\n\n      const reservoir = new Reservoir<string>(args.requestedCount);\n      // Pool-filter audit accumulators — persisted to waveRuns at end of pool\n      // selection so any past wave's filter behavior is auditable from the\n      // row alone (no log archaeology).","sourceCodeStart":704,"sourceCodeEnd":740,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/convex/broadcast/waveRuns.ts#L704-L740","documentation":"Lease acquisition failure in pickWaveAction: _claimWaveRunLease refused the claim (the reason and current holder are embedded). Another wave run is active or a stale lease is held, so this pick cannot start without double-sending risk.","triggerScenarios":"Thrown at convex/broadcast/waveRuns.ts:722 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Read the embedded reason: a live lease means wait for the current wave to finish; a stale lease means use the documented lease-release or recovery flow","Do not bypass the lease — retrying concurrently risks duplicate segments and sends"],"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-14T00:17:10.932Z"}