koala73/worldmonitor · error · Error

[clearPartialFailure] no ramp configured

Error message

[clearPartialFailure] no ramp configured

What it means

clearPartialFailure resets a partial-failure run state so a fresh wave can be attempted. It loads the config via loadConfig and throws if no row exists, since there is no partial-failure state to clear on a non-existent ramp.

Source

Thrown at convex/broadcast/rampRunner.ts:297

 * audience tables AND verify no broadcast in the Resend dashboard before
 * calling.
 *
 * For ANY case where the export ran (segment created, contacts stamped,
 * broadcast created, or send fired), use `recoverFromPartialFailure` —
 * `manual-finished` if the wave actually went out, `discard-and-rotate` if
 * not.
 */
export const clearPartialFailure = internalMutation({
  args: {
    reason: v.string(),
    // Literal-true forces the operator to actively assert "I have verified no
    // export happened." A future caller can't accidentally pass `false` to
    // bypass this.
    confirmNoExport: v.literal(true),
  },
  handler: async (ctx, { reason }) => {
    const row = await loadConfig(ctx);
    if (!row) throw new Error("[clearPartialFailure] no ramp configured");
    if (row.lastRunStatus !== "partial-failure") {
      return {
        ok: true as const,
        noop: true as const,
        currentStatus: row.lastRunStatus,
      };
    }
    // Fail-closed: if any pending-progress marker exists, the export DID make
    // progress past `assignAndExportWave` — clearing here would mask a stamped
    // / sent wave. Force the operator to use recoverFromPartialFailure.
    if (
      row.pendingWaveLabel ||
      row.pendingSegmentId ||
      row.pendingBroadcastId
    ) {
      throw new Error(
        `[clearPartialFailure] refused: pending progress markers present (waveLabel=${row.pendingWaveLabel ?? "-"}, segmentId=${row.pendingSegmentId ?? "-"}, broadcastId=${row.pendingBroadcastId ?? "-"}). The export DID run; clearing here would mask stamped contacts. Use recoverFromPartialFailure instead.`,
      );

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Preflight with getRampStatus; if {configured:false} there is nothing to clear.
  2. If the ramp was aborted intentionally, the partial-failure state was deleted with it — no action required.
  3. Re-seed with initRamp for a fresh ramp if a new launch is intended.

Example fix

// before
await ctx.runMutation(internal.broadcast.rampRunner.clearPartialFailure, { reason, confirmNoExport: true });

// after
const status = await ctx.runQuery(internal.broadcast.rampRunner.getRampStatus, {});
if (!status.configured) return { skipped: 'no ramp configured' };
await ctx.runMutation(internal.broadcast.rampRunner.clearPartialFailure, { reason, confirmNoExport: true });
Defensive patterns

Strategy: validation

Validate before calling

// Preflight before clearPartialFailure
const status = await ctx.runQuery(internal.broadcast.rampRunner.getRampStatus, {});
if (!status.configured) {
  return { skipped: 'no ramp configured — nothing to clear' };
}

Type guard

function isConfigured(s: { configured: boolean }): s is { configured: true; lastRunStatus?: string } {
  return s.configured === true;
}

Prevention

When it happens

Trigger: Calling clearPartialFailure before initRamp, after abortRamp deleted the row, or when the ramp config was never seeded in this deployment.

Common situations: Recovery runbook run after the ramp was already aborted; stale automation firing against an unseeded Convex project.

Related errors


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/b2cf2e4bd2b70835. Report an issue: GitHub.