koala73/worldmonitor · warning · ValidationError
alertThreshold must be between 0 and 100
Error message
alertThreshold must be between 0 and 100
What it means
registerWebhook re-enforces the inclusive 0..100 range on alertThreshold even though buf.validate normally enforces it at the wire layer, because direct handler calls (internal jobs, test harnesses, transports that bypass proto validation) would otherwise store out-of-range values. undefined means the partner omitted the field and defaults to 50; an explicit 0 is preserved and means deliver every alert.
Source
Thrown at server/worldmonitor/shipping/v2/register-webhook.ts:78
}
const chokepointIds = Array.isArray(req.chokepointIds) ? req.chokepointIds : [];
const invalidCp = chokepointIds.find(id => !VALID_CHOKEPOINT_IDS.has(id));
if (invalidCp) {
throw new ValidationError([
{ field: 'chokepointIds', description: `Unknown chokepoint ID: ${invalidCp}` },
]);
}
// alert_threshold is `optional int32` (#3242 followup #4) — undefined means
// the partner omitted the field, so apply the legacy default of 50. An
// explicit 0 is preserved (deliver every alert). The 0..100 range is
// normally enforced by buf.validate at the wire layer, but we re-enforce
// it here so direct handler calls (internal jobs, test harnesses, future
// transports that bypass buf.validate) can't store out-of-range values.
const alertThreshold = req.alertThreshold ?? 50;
if (alertThreshold < 0 || alertThreshold > 100) {
throw new ValidationError([
{ field: 'alertThreshold', description: 'alertThreshold must be between 0 and 100' },
]);
}
const ownerTag = await callerFingerprint(ctx.request, apiKeyResult.credential);
const newSubscriberId = generateSubscriberId();
const secret = await generateSecret();
const record: WebhookRecord = {
subscriberId: newSubscriberId,
ownerTag,
callbackUrl,
chokepointIds: chokepointIds.length ? chokepointIds : [...VALID_CHOKEPOINT_IDS],
alertThreshold,
createdAt: new Date().toISOString(),
active: true,
secret,
};View on GitHub (pinned to eeab0a219f)
Solutions
- Clamp or validate alertThreshold to an integer in 0..100 before building the request
- Keep explicit 0 if 'deliver every alert' was intended — only <0 or >100 throws
- For direct handler calls, route requests through the same validation path as the wire layer or validate first
Example fix
// before
registerWebhook(ctx, { callbackUrl, chokepointIds, alertThreshold: 150 });
// after
registerWebhook(ctx, {
callbackUrl,
chokepointIds,
alertThreshold: Math.min(100, Math.max(0, Math.round(150))),
}); Defensive patterns
Strategy: validation
Validate before calling
if (req.alertThreshold !== undefined && !(Number.isInteger(req.alertThreshold) && req.alertThreshold >= 0 && req.alertThreshold <= 100)) throw new RangeError('alertThreshold must be an integer in 0..100'); Type guard
const isAlertThreshold = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v >= 0 && v <= 100;
Try / catch
catch (e) { if (e?.details?.[0]?.field === 'alertThreshold') { clamp to [0,100] and re-submit, or omit the field to take the default 50 } else throw e; } Prevention
- Remember undefined defaults to 50 and explicit 0 is legal — only out-of-range values throw
- Constrain UI inputs (sliders/number fields) to 0..100 integers
- Direct handler calls in tests bypass buf.validate: validate requests yourself
When it happens
Trigger: Direct (non-HTTP) invocation of the registerWebhook handler with alertThreshold below 0 or above 100; a transport wired without buf.validate; hand-built request objects in tests or internal jobs. Over-the-wire calls are normally stopped earlier by buf.validate with a different error shape.
Common situations: Unit tests constructing requests by hand; a UI slider allowing out-of-range values; internal automation jobs calling the handler directly; a new RPC transport added without the validation middleware.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- callbackUrl is required
- callbackUrl is not allowed
- Unknown chokepoint ID: ${invalidCp}
- callbackUrl is not a valid URL
- callbackUrl must use https
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/4353b7f527868e5d.
Report an issue: GitHub.