hcengineering/platform · error
Interval must be a finite number >= 1 (seconds)
Error message
Interval must be a finite number >= 1 (seconds)
What it means
register schedules a TickHandler to fire every `interval` seconds, so the interval must be a finite number >= 1. NaN, Infinity, 0, negatives, and fractional sub-second intervals are rejected at registration time. It returns an unregister function only when validation passes.
Source
Thrown at foundations/net/packages/core/src/utils.ts:48
tickListeners = new Map<number, (() => void)[]>()
started: boolean = false
constructor (readonly tps: number) {
if (tps > 1000 || tps < 1) {
throw new Error('Ticks per second has an invalid value: must be >= 1 && <= 1000')
}
}
now (): number {
// Use performance.now() when available, otherwise fall back to Date.now()
// performance is available in recent Node versions, but guard for portability.
return (globalThis as any).performance?.now?.() ?? Date.now()
}
register (handler: TickHandler, interval: number): () => void {
if (!Number.isFinite(interval) || interval < 1) {
throw new Error('Interval must be a finite number >= 1 (seconds)')
}
const handlerId = this.hashCounter++
this.handlers.set(handlerId, [handler, handlerId % this.tps, interval])
return () => {
this.handlers.delete(handlerId)
}
}
async tick (): Promise<void> {
this._tick++
// Handle tick listeners
if (this.tickListeners.size > 0) {
const listeners = this.tickListeners.get(this._tick) ?? []
this.tickListeners.delete(this._tick)
for (const listener of listeners) {
try {
listener()View on GitHub (pinned to 63e28dc964)
Solutions
- Pass a whole number of seconds >= 1 (e.g. register(handler, 5)).
- Convert from milliseconds explicitly: Math.ceil(ms / 1000), and guard against < 1.
- Sanitize the source value: Number.isFinite(v) ? v : fallback before calling register.
- If you need sub-second granularity, use setInterval directly or raise tps instead of passing fractional intervals.
Example fix
// before ticker.register(handler, Number(process.env.INTERVAL_MS)) // NaN or ms-as-seconds // after const secs = Math.max(1, Math.ceil(Number(process.env.INTERVAL_MS ?? 1000) / 1000)) ticker.register(handler, secs)
Defensive patterns
Strategy: validation
Validate before calling
function toIntervalSeconds(raw: unknown, fallback = 5): number {
const n = typeof raw === 'number' ? raw : Number(raw)
if (!Number.isFinite(n)) return fallback
return Math.max(1, Math.ceil(n)) // supports ms callers via explicit conversion upstream
}
ticker.register(handler, toIntervalSeconds(process.env.HANDLER_INTERVAL_S)) Type guard
function isValidInterval(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v) && v >= 1
} Try / catch
try {
const cancel = ticker.register(handler, interval)
registered.push(cancel)
} catch (e) {
if ((e as Error).message.includes('Interval must be')) {
console.warn(`invalid interval ${interval}, using 5s`)
registered.push(ticker.register(handler, 5))
} else throw e
} Prevention
- Convert milliseconds to seconds explicitly (Math.ceil(ms/1000)) when migrating from ms-based timers.
- Sanitize env/config numbers with Number.isFinite before use.
- Never pass 0 or fractional values; the minimum interval is 1 second by design.
- Keep a named constant for default intervals instead of inlining raw numbers from config.
When it happens
Trigger: Calling ticker.register(handler, interval) with interval = 0, a negative number, NaN (e.g. from parseInt of a bad env var), or Infinity — all of which fail the Number.isFinite/interval < 1 check.
Common situations: Env/config strings like '' or 'abc' converting to NaN; mistaking milliseconds for seconds (500 intended as 0.5s); uninitialized variable defaulting to undefined→NaN; unit confusion after migrating from a ms-based timer API.
Related errors
- Ticks per second has an invalid value: must be >= 1 && <= 10
- No screen access granted
- Accounts url not specified
- Ticks must be >= 1
- Endpoint value is not specified
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/a5e23f1786a0b2b4.
Report an issue: GitHub.