koala73/worldmonitor · error · Error

[_markPickComplete] run

Error message

[_markPickComplete] run ${args.runId} is ${run.status}, expected picking

What it means

State-machine guard in _markPickComplete: the waveRuns row's status is not 'picking' (the actual status is embedded). The transition to 'segment-created' is only legal from 'picking'; a different status means another writer — a competing pick, an operator action, or a prior completion — already moved the run.

Solutions

  1. Read the embedded actual status: 'segment-created' or 'sent' means the pick already completed — treat as idempotent success
  2. 'failed' or 'purged' means the run was aborted; do not force the transition, start a new wave instead
  3. Prevent concurrent pickWaveAction invocations for the same run (the lease claim should serialize them)
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at convex/broadcast/waveRuns.ts:604 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/5327feddd25ee194. Report an issue: GitHub.

Appendix: source

Thrown at convex/broadcast/waveRuns.ts:620

/**
 * Transition a `picking`-status run to `segment-created` after pickWaveAction
 * has finished sampling, persisting, and creating the Resend segment.
 */
export const _markPickComplete = internalMutation({
  args: {
    runId: v.string(),
    segmentId: v.string(),
    totalCount: v.number(),
    underfilled: v.boolean(),
  },
  handler: async (ctx, args) => {
    const run = await ctx.db
      .query("waveRuns")
      .withIndex("by_runId", (q) => q.eq("runId", args.runId))
      .unique();
    if (!run) throw new Error(`[_markPickComplete] no run ${args.runId}`);
    if (run.status !== "picking") {
      throw new Error(
        `[_markPickComplete] run ${args.runId} is ${run.status}, expected picking`,
      );
    }
    const now = Date.now();
    await ctx.db.patch(run._id, {
      status: "segment-created",
      segmentId: args.segmentId,
      totalCount: args.totalCount,
      underfilled: args.underfilled,
      updatedAt: now,
    });
    return { ok: true };
  },
});

/**
 * Record a pick-phase failure. Lease policy depends on substatus:
 *   - 'empty-pool' clears the lease (terminal no-op; operator may retry next cycle)

View on GitHub (pinned to 7d06c8633d)