denoland/deno · error · TypeError
ERR_INVALID_THIS
ERR_INVALID_THIS
Error message
Value of "this" must be of type EventEmitterReferencingAsyncResource
What it means
The internal class EventEmitterReferencingAsyncResource (built lazily by getEventEmitterAsyncResource) stores the emitter in the kEventEmitter symbol property set by its constructor; its eventEmitter getter throws ERR_INVALID_THIS at _events.mjs:1244 when that property is undefined. That only happens when the getter runs with a receiver that never executed the constructor - i.e. the getter was detached from a real instance and invoked with the wrong 'this'.
Source
Thrown at ext/node/polyfills/_events.mjs:1244
const kAsyncResource = Symbol("kAsyncResource");
const kEventEmitter = Symbol("kEventEmitter");
// EventEmitterAsyncResource and its helper class are defined lazily to avoid
// eagerly loading node:async_hooks (which provides AsyncResource).
let _EventEmitterAsyncResource;
function getEventEmitterAsyncResource() {
if (_EventEmitterAsyncResource) return _EventEmitterAsyncResource;
const { AsyncResource } = lazyAsyncHooks();
class EventEmitterReferencingAsyncResource extends AsyncResource {
constructor(ee, type, options) {
super(type, options);
this[kEventEmitter] = ee;
}
get eventEmitter() {
if (this[kEventEmitter] === undefined) {
throw new ERR_INVALID_THIS("EventEmitterReferencingAsyncResource");
}
return this[kEventEmitter];
}
}
_EventEmitterAsyncResource = class EventEmitterAsyncResource
extends EventEmitter {
constructor(options = undefined) {
let name;
if (typeof options === "string") {
name = options;
options = undefined;
} else {
if (new.target === _EventEmitterAsyncResource) {
validateString(options?.name, "options.name");
}
name = options?.name || new.target.name;
}View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Always access the property on the instance itself: resource.eventEmitter, never a detached getter
- Do not destructure getters; read them directly or via a helper that keeps the receiver
- In subclasses, always call super(...) so the internal symbol properties are installed
- Verify the receiver with instanceof before touching the getter in generic code
Example fix
// before
const { eventEmitter } = asyncResource; // 'this' lost when invoked later
eventEmitter.emit('x');
// after
asyncResource.eventEmitter.emit('x'); Defensive patterns
Strategy: type-guard
Validate before calling
const { EventEmitterAsyncResource } = require('node:events');
if (!(resource instanceof EventEmitterAsyncResource)) {
throw new TypeError('expected EventEmitterAsyncResource');
}
const ee = resource.eventEmitter; Type guard
const isEEAR = (v) =>
v instanceof require('node:events').EventEmitterAsyncResource; Prevention
- Access eventEmitter as a property on the instance; never destructure getters
- Call super() in all subclass constructors
- Reject prototype-only objects in APIs: always construct with new
When it happens
Trigger: Extracting the getter and calling it bare or via .call(): const { eventEmitter } = asyncResource; or Object.getOwnPropertyDescriptor(proto, 'eventEmitter').get.call({}); calling the getter through Reflect.apply with a foreign receiver; a subclass that overrides the constructor without calling super() so kEventEmitter is never assigned; accessing .eventEmitter on an object created via Object.create(proto) instead of new.
Common situations: Destructuring-style bugs (const { eventEmitter } = resource); wrapper or proxy code that rebinds getters; copy-style clones that copy accessors but not symbol properties; async-hooks experimentation.
Related errors
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/dd462b0130e0b169.
Report an issue: GitHub.