hcengineering/platform · error
Ticks per second has an invalid value: must be >= 1 && <= 10
Error message
Ticks per second has an invalid value: must be >= 1 && <= 1000
What it means
The tick/timer utility validates its tps (ticks per second) in the constructor and rejects any value outside the 1–1000 inclusive range. A tps above 1000 would require sub-millisecond timers the runtime cannot honor, and values below 1 are meaningless. The constructor fails fast so an invalid clock is never used.
Source
Thrown at foundations/net/packages/core/src/utils.ts:36
}
/**
* Handles a time unification and inform about ticks.
*/
export class TickManagerImpl implements TickManager {
handlers = new Map<number, [TickHandler, number, number]>()
hashCounter: number = 0
_tick: number = 0
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)
}View on GitHub (pinned to 63e28dc964)
Solutions
- Pass a tps between 1 and 1000 inclusive (e.g. new Ticker(60)).
- Sanitize config: Number.parseInt the env value and clamp it with Math.min(1000, Math.max(1, value)).
- Provide a sane default (e.g. 60) when the config value is missing or invalid instead of passing 0/undefined.
- If you need sub-millisecond resolution, this utility cannot provide it; redesign the timing loop instead of raising tps.
Example fix
// before const ticker = new Ticker(Number(process.env.TPS)) // undefined -> invalid // after const tps = Math.min(1000, Math.max(1, Number(process.env.TPS ?? 60))) const ticker = new Ticker(tps)
Defensive patterns
Strategy: validation
Validate before calling
function parseTps(raw: unknown, fallback = 60): number {
const n = typeof raw === 'number' ? raw : Number(raw)
if (!Number.isFinite(n) || n < 1 || n > 1000) return fallback
return Math.floor(n)
}
const ticker = new Ticker(parseTps(process.env.TPS)) Type guard
function isValidTps(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v) && Number.isInteger(v) && v >= 1 && v <= 1000
} Try / catch
let ticker: Ticker
try {
ticker = new Ticker(configuredTps)
} catch (e) {
if ((e as Error).message.includes('Ticks per second')) {
console.warn(`invalid tps ${configuredTps}, falling back to 60`)
ticker = new Ticker(60)
} else throw e
} Prevention
- Clamp tps from config/env with Math.min(1000, Math.max(1, value)).
- Provide a documented default (e.g. 60) and validate config at boot.
- Unit-test config parsing so empty/NaN values never reach the constructor.
- Remember tps is ticks per second — never pass millisecond durations as tps.
When it happens
Trigger: Constructing the tick utility with tps = 0, a negative number, NaN-adjacent values comparing oddly, or a value > 1000 (e.g. passing milliseconds instead of seconds-per-tick, or multiplying tps by 1000 by mistake).
Common situations: Confusing tps with interval milliseconds (1000 used as '1 second'); loading tps from config/env where an empty or malformed string yields a bad number; defaulting logic producing 0 when a config key is missing.
Related errors
- Interval must be a finite number >= 1 (seconds)
- 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/bd2d4ccb1457251d.
Report an issue: GitHub.