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
- Read the embedded actual status: 'segment-created' or 'sent' means the pick already completed — treat as idempotent success
- 'failed' or 'purged' means the run was aborted; do not force the transition, start a new wave instead
- 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)