koala73/worldmonitor · error · Error

[_recordPendingBroadcast] lease lost: expected runId=

Error message

[_recordPendingBroadcast] lease lost: expected runId=${args.runId}, found ${row.pendingRunId ?? "<cleared>"}. Refusing to persist broadcast progress — operator/another run owns the state.

What it means

Error "[_recordPendingBroadcast] lease lost: expected runId=${args.runId}, found ${row.pendingRunId ?? "<cleared>"}. Refusing to persist broadcast progress — operator/another run owns the state." thrown in koala73/worldmonitor.

Solutions

  1. Identify the new lease owner (operator forceReleaseLease or a competing run) from Convex logs before acting
  2. Do not blindly retry — the broadcast was already created in Resend; recover via recoverFromPartialFailure with the known broadcastId instead of creating a duplicate
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at convex/broadcast/rampRunner.ts:752 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-08-21). Data as JSON: /api/errors/e28790e95500eb28. Report an issue: GitHub.

Appendix: source

Thrown at convex/broadcast/rampRunner.ts:754

/**
 * Persist post-`createProLaunchBroadcast` progress. Called by the runner
 * AFTER `createProLaunchBroadcast` returns successfully. Lets
 * `recoverFromPartialFailure` recover the broadcastId without
 * operator-supplied metadata if the action dies between this point and a
 * successful `_recordWaveSent`.
 *
 * Lease-validating: same semantics as `_recordPendingExport`.
 */
export const _recordPendingBroadcast = internalMutation({
  args: {
    runId: v.string(),
    broadcastId: v.string(),
  },
  handler: async (ctx, args) => {
    const row = await loadConfig(ctx);
    if (!row) throw new Error("[_recordPendingBroadcast] no ramp configured");
    if (row.pendingRunId !== args.runId) {
      throw new Error(
        `[_recordPendingBroadcast] lease lost: expected runId=${args.runId}, found ${row.pendingRunId ?? "<cleared>"}. Refusing to persist broadcast progress — operator/another run owns the state.`,
      );
    }
    await ctx.db.patch(row._id, {
      pendingBroadcastId: args.broadcastId,
      pendingBroadcastAt: Date.now(),
    });
    return { ok: true as const };
  },
});

/**
 * Internal mutation that the action calls to atomically advance the tier +
 * record a successful wave-send. Validates that the lease still belongs to
 * this runId AND clears all pending-progress markers.
 */
export const _recordWaveSent = internalMutation({
  args: {

View on GitHub (pinned to 7d06c8633d)