ReactiveX/rxjs · error · TypeError
MarbleContext.setInterval: callback must be a function
Error message
MarbleContext.setInterval: callback must be a function
What it means
The TestScheduler's patched setInterval requires a function callback, matching strict modern timer semantics. Passing a string (old IE-style eval form), null, or undefined throws instead of scheduling an interval.
Source
Thrown at packages/rxjs/src/testing/index.ts:90
return new Promise((resolve) => {
patched(() => resolve(value!), delay ?? 0);
});
};
return patched;
})();
#clearTimeout: typeof globalThis.clearTimeout = (id: Parameters<typeof originalClearTimeout>[0]) => {
if (id === undefined) return;
this.#removeTimer(+id);
};
#setInterval: typeof globalThis.setInterval = (() => {
const patched = (callback: TimerHandler, delay = 0, ...args: any[]): any => {
const id = ++this.#timerId;
const time = this.#now + delay;
if (typeof callback !== 'function') {
throw new TypeError('MarbleContext.setInterval: callback must be a function');
}
const item: TimerQueueItem = { id, callback: callback as (...args: any[]) => void, delay, time, type: 'interval', args };
this.#addTimer(item);
if (this.#shouldUseNodeTimeout) {
let ref = false;
const nodeTimeout = {
ref: () => {
ref = true;
return nodeTimeout;
},
unref: () => {
ref = false;
return nodeTimeout;
},
hasRef: () => {
return ref;
},View on GitHub (pinned to 54796b38a5)
Solutions
- Pass a function reference or arrow function: setInterval(() => tick(), 1000)
- Guard forwarding wrappers: if (typeof cb === 'function') setInterval(cb, ms)
- Initialize callback variables before use; make callback params required in types
Example fix
// before
setInterval('tick()', 1000);
// after
setInterval(tick, 1000); // or setInterval(() => tick(), 1000) Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof callback !== 'function') throw new TypeError('callback must be a function');
setInterval(callback, delay); Type guard
const isFn = (cb: unknown): cb is (...args: any[]) => void => typeof cb === 'function';
Prevention
- Replace string callbacks with arrow functions before marble testing
- Initialize callback variables before calling setInterval
- Make callback parameters required in wrapper signatures
When it happens
Trigger: Inside TestScheduler.run(() => { setInterval('tick()', 1000) }) or setInterval(undefined, 1000) from a forwarding bug in code under test.
Common situations: Porting legacy code that used string callbacks with setInterval, or wrappers like myInterval(cb) that pass an uninitialized cb variable.
Related errors
AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28).
Data as JSON: /api/errors/95faa9ec969ee3df.
Report an issue: GitHub.