koala73/worldmonitor · error · Error
[initRamp] seedLastWaveBroadcastId and seedLastWaveSentAt mu
Error message
[initRamp] seedLastWaveBroadcastId and seedLastWaveSentAt must be provided together.
What it means
Thrown by initRamp when exactly one of seedLastWaveBroadcastId and seedLastWaveSentAt is provided. These two fields are a required pair because the kill-gate logic needs both the broadcast id (to fetch bounce/complaint stats) and the sent-at timestamp (to scope the stats window). Providing only one yields an inconsistent seed state.
Source
Thrown at convex/broadcast/rampRunner.ts:175
// non-English locale (canonical via `users.localePrimary`, fallback
// via email-TLD heuristic for legacy waitlist registrants without a
// users row). Default false to preserve byte-identical behavior for
// existing ramps. Operators opt in for wave-8+ deliberately. Run
// `_dryRunNonEnglishExclusion` first to inspect impact before flipping.
excludeNonEnglish: v.optional(v.boolean()),
},
handler: async (ctx, args) => {
if (args.rampCurve.length === 0) {
throw new Error("[initRamp] rampCurve must be non-empty");
}
if (args.rampCurve.some((n) => !Number.isInteger(n) || n <= 0)) {
throw new Error("[initRamp] rampCurve entries must be positive integers");
}
const offset = args.waveLabelOffset ?? 0;
const hasSeedBroadcast = !!args.seedLastWaveBroadcastId;
const hasSeedSentAt = typeof args.seedLastWaveSentAt === "number";
if (hasSeedBroadcast !== hasSeedSentAt) {
throw new Error(
"[initRamp] seedLastWaveBroadcastId and seedLastWaveSentAt must be provided together.",
);
}
if (offset > 0 && !hasSeedBroadcast) {
throw new Error(
`[initRamp] waveLabelOffset=${offset} signals resumption after manual waves; seedLastWaveBroadcastId + seedLastWaveSentAt are required so the first cron tick can apply the kill-gate against the prior wave. Pass them, or set waveLabelOffset=0 to start a fresh ramp.`,
);
}
const existing = await ctx.db
.query("broadcastRampConfig")
.withIndex("by_key", (q) => q.eq("key", RAMP_KEY))
.first();
if (existing) {
throw new Error(
`[initRamp] ramp already configured (active=${existing.active}, tier=${existing.currentTier}). Run abortRamp first if reconfiguring.`,
);
}
await ctx.db.insert("broadcastRampConfig", {View on GitHub (pinned to ffec79ac33)
Solutions
- Provide both seedLastWaveBroadcastId AND seedLastWaveSentAt together, or omit both entirely.
- Look up the prior wave's record to obtain both values consistently.
Example fix
// before
await initRamp(ctx, {
rampCurve: [100, 250], waveLabelPrefix: "w",
seedLastWaveBroadcastId: "abc", // seedLastWaveSentAt missing
});
// after — provide both (or neither)
await initRamp(ctx, {
rampCurve: [100, 250], waveLabelPrefix: "w",
seedLastWaveBroadcastId: "abc",
seedLastWaveSentAt: Date.parse("2024-10-15T12:00:00Z"),
}); Defensive patterns
Strategy: validation
Validate before calling
const hasBroadcast = !!args.seedLastWaveBroadcastId;
const hasSentAt = typeof args.seedLastWaveSentAt === "number";
if (hasBroadcast !== hasSentAt) {
throw new Error("Provide both seedLastWaveBroadcastId and seedLastWaveSentAt, or neither");
}
await initRamp(ctx, args); Prevention
- Always pass seed fields as a pair sourced from the same prior-wave record.
- Add a config-lint check that the two seed fields are both present or both absent.
When it happens
Trigger: Calling initRamp with seedLastWaveBroadcastId set but seedLastWaveSentAt omitted (or vice versa); a config builder that populated one field from a prior-wave record but forgot the other.
Common situations: Operator manually filled in the broadcast id from the Resend dashboard but didn't look up the sent timestamp; a script pulled fields from an incomplete prior-wave record.
Related errors
- [initRamp] rampCurve must be non-empty
- [initRamp] waveLabelOffset=${offset} signals resumption afte
- [initRamp] rampCurve entries must be positive integers
- [initRamp] ramp already configured (active=${existing.active
- [backfillCanary250] RESEND_API_KEY not set — run with the sa
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/1d4d7f40ebbe8e78.
Report an issue: GitHub.