koala73/worldmonitor · critical · Error

[runDailyRamp] rampCurve[${nextTier}] is undefined despite b

Error message

[runDailyRamp] rampCurve[${nextTier}] is undefined despite bounds check — config corruption?

What it means

In runDailyRamp, after a bounds check confirms nextTier < rampCurve.length, the code indexes rampCurve[nextTier] and guards against undefined as a defensive measure (it quiets noUncheckedIndexedAccess and protects against a future code change breaking the bounds check). If this throw fires, the rampCurve array was mutated/shortened between the bounds check and the index, or the persisted config is internally inconsistent.

Source

Thrown at convex/broadcast/rampRunner.ts:1025

      }
    }

    // ──── Step 2: figure out which tier to send next ────
    const nextTier = row.currentTier + 1;
    if (nextTier >= row.rampCurve.length) {
      console.log("[runDailyRamp] ramp curve complete — deactivating");
      await ctx.runMutation(
        internal.broadcast.rampRunner._recordRunOutcome,
        { status: "ramp-complete", deactivate: true },
      );
      return { status: "ramp-complete" };
    }
    // Bounds-checked above; explicit guard quiets noUncheckedIndexedAccess
    // and protects against a future code change that breaks the
    // bounds check above without realising this index is now unsafe.
    const count = row.rampCurve[nextTier];
    if (count === undefined) {
      throw new Error(
        `[runDailyRamp] rampCurve[${nextTier}] is undefined despite bounds check — config corruption?`,
      );
    }
    const waveLabel = `${row.waveLabelPrefix}-${nextTier + row.waveLabelOffset}`;

    // ──── Step 3: in-flight guard via the new wave-loading state machine ────
    // PR 2 (post-launch-stabilization plan, 2026-04-29) replaces the
    // monolithic assignAndExportWave + createProLaunchBroadcast + sendProLaunchBroadcast
    // chain with a self-driving multi-step pipeline that fits within the
    // Convex 10-min action runtime budget at any wave size. The state lives
    // on `waveRuns` + `wavePickedContacts`. See `convex/broadcast/waveRuns.ts`.
    //
    // The legacy `_claimTierForRun` + `_recordPendingExport` + `_recordPendingBroadcast`
    // + `_recordWaveSent` + `_recordRunOutcome` mutations remain in this
    // module so the operator-recovery commands (`recoverFromPartialFailure`,
    // `clearPartialFailure`, `forceReleaseLease`) keep working on any
    // legacy partial-failure rows. New runs go through the state machine.
    //

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Inspect the broadcastRampConfig row's rampCurve and currentTier directly — confirm internal consistency.
  2. If corrupted, abortRamp and re-seed via initRamp with a valid rampCurve.
  3. Add a guard around any code path that mutates rampCurve post-init (it should be immutable after initRamp).
Defensive patterns

Strategy: validation

Validate before calling

// Validate config consistency before the runner indexes rampCurve
const row = await ctx.db.query('broadcastRampConfig').withIndex('by_key', (q) => q.eq('key', 'current')).first();
if (!row) throw new Error('no ramp configured');
const nextTier = row.currentTier + 1;
if (nextTier >= row.rampCurve.length || row.rampCurve[nextTier] === undefined) {
  throw new Error(`rampCurve inconsistent at nextTier=${nextTier} (length=${row.rampCurve.length}) — config corruption; abort+reseed.`);
}

Type guard

function rampCurveIsConsistent(row: { currentTier: number; rampCurve: number[] }): boolean {
  return Array.isArray(row.rampCurve) && row.rampCurve.length > 0 && row.rampCurve.every((n) => typeof n === 'number' && Number.isInteger(n) && n > 0);
}

Prevention

When it happens

Trigger: The broadcastRampConfig.rampCurve array was concurrently shortened (another mutation) between the length check and the index read; a corrupted/hand-edited config row has a rampCurve with holes or shorter than its recorded length; a Convex OCC retry saw a stale row.

Common situations: An operator mutation rewrote rampCurve mid-tick; a buggy script wrote an inconsistent row; extremely rare race on config rewrite.

Related errors


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