{"record":{"id":"4d4ea7f1aac5d2f5","repo":"denoland/deno","slug":"err-invalid-this-4d4ea7","errorCode":"ERR_INVALID_THIS","errorMessage":"Value of \"this\" must be of type Scheduler","messagePattern":"Value of \"this\" must be of type Scheduler","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/timers.ts","lineNumber":365,"sourceCode":"    }\n    if (onCancel) {\n      signal?.removeEventListener(\"abort\", onCancel);\n    }\n  }\n}\n\nconst promises = {\n  setTimeout: setTimeoutPromise,\n  setImmediate: setImmediatePromise,\n  setInterval: setIntervalAsync,\n};\n\n// There is exactly one `scheduler`, so identity is the check: a\n// prototype-linked object, or one carrying whatever properties the real\n// instance has, is still a foreign receiver.\nfunction validateScheduler(self: unknown) {\n  if (self !== scheduler) {\n    throw new ERR_INVALID_THIS(\"Scheduler\");\n  }\n}\n\nclass Scheduler {\n  constructor() {\n    throw new ERR_ILLEGAL_CONSTRUCTOR();\n  }\n  // Not `async`: the `this` check has to reject a foreign receiver\n  // synchronously rather than returning a rejected promise.\n  wait(\n    delay: number,\n    options?: { signal?: AbortSignal },\n  ): Promise<void> {\n    validateScheduler(this);\n    return setTimeoutPromise(delay, undefined, options);\n  }\n  yield() {\n    validateScheduler(this);","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/timers.ts#L347-L383","documentation":"The node:timers scheduler is a singleton; its methods validate the receiver by identity (self === scheduler) and throw ERR_INVALID_THIS for any other this. The constructor throws ERR_ILLEGAL_CONSTRUCTOR, so there is exactly one instance and prototype-linked or property-cloned look-alikes are rejected.","triggerScenarios":"const { wait } = scheduler; wait(100) (detached method); passing the bare function as a callback: setTimeout(scheduler.wait, 10, 100); scheduler.wait.call({}, 100).","commonSituations":"Destructuring for convenience; wiring scheduler methods into generic dispatchers or option objects; wrapper functions losing the receiver.","solutions":["Always call through the object: scheduler.wait(100, { signal })","Bind when detaching: const wait = scheduler.wait.bind(scheduler)","Wrap in an arrow function: (delay, opts) => scheduler.wait(delay, opts)"],"exampleFix":"// before\nconst { wait } = scheduler;\nwait(100); // throws ERR_INVALID_THIS\n\n// after\nconst wait = scheduler.wait.bind(scheduler);\nwait(100);","handlingStrategy":"validation","validationCode":"const schedulerWait = scheduler.wait.bind(scheduler);\n// or wrap: const schedulerWait = (d: number, o?: { signal?: AbortSignal }) => scheduler.wait(d, o);","typeGuard":null,"tryCatchPattern":"try { scheduler.wait.call(scheduler, 100); } catch (e) { if (e.code === 'ERR_INVALID_THIS') throw new Error('scheduler methods must run on the scheduler instance'); else throw e; }","preventionTips":["Never destructure scheduler methods; call them as scheduler.wait(...)","Bind once at module scope when passing the method around","Wrap scheduler calls in small named helpers in your codebase"],"tags":["timers","scheduler","invalid-this"],"backgroundTag":"invalid-this","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}