{"record":{"id":"258f59a2be0be599","repo":"denoland/deno","slug":"illegal-invocation-258f59","errorCode":null,"errorMessage":"Illegal invocation","messagePattern":"Illegal invocation","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/13_message_port.js","lineNumber":150,"sourceCode":"const _messageEventListenerCount = Symbol(\"messageEventListenerCount\");\nconst nodeWorkerThreadCloseCb = Symbol(\"nodeWorkerThreadCloseCb\");\nconst nodeWorkerThreadCloseCbInvoked = Symbol(\"nodeWorkerThreadCloseCbInvoked\");\nconst refMessagePort = Symbol(\"refMessagePort\");\n/** It is used by 99_main.js and worker_threads to\n * unref/ref on the global message event handler count. */\nconst unrefParentPort = Symbol(\"unrefParentPort\");\n\n/** @type {WeakMap<MessagePort, number | null>} */\nconst messagePortIds = new SafeWeakMap();\n\n/**\n * @param {MessagePort} port\n * @returns {number | null}\n */\nfunction getMessagePortId(port) {\n  const id = WeakMapPrototypeGet(messagePortIds, port);\n  if (id === undefined) {\n    throw new TypeError(\"Illegal invocation\");\n  }\n  return id;\n}\n\n/**\n * @param {MessagePort} port\n * @param {number | null} id\n */\nfunction setMessagePortId(port, id) {\n  WeakMapPrototypeSet(messagePortIds, port, id);\n}\n\n/**\n * @param {MessagePort} port\n * @returns {number | null}\n */\nfunction takeMessagePortId(port) {\n  const id = getMessagePortId(port);","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/13_message_port.js#L132-L168","documentation":"MessagePort methods resolve their receiver through the module-private `messagePortIds` WeakMap (ext/web/13_message_port.js:150). When a method runs with a `this` that is not a live runtime-created MessagePort, the WeakMap lookup returns undefined and Deno throws TypeError \"Illegal invocation\" — the same semantics as the WebIDL brand check. It means the receiver never had (or no longer resolves to) an entangled port id.","triggerScenarios":"Detaching the method from its owner: `const post = port.postMessage; post('x')`; calling `MessagePort.prototype.postMessage.call(fakeThis, ...)`; invoking methods on a mock, Proxy wrapper, or hand-crafted object that satisfies the brand check but was never registered in the WeakMap.","commonSituations":"Passing `port.postMessage` as a bare callback (e.g. `items.forEach(port.postMessage)`); dependency-injection test doubles replacing MessagePort; wrapping ports in Proxy for logging; code copied between realms/workers.","solutions":["Bind extracted methods: `const post = port.postMessage.bind(port)`.","Wrap in an arrow function: `const post = (...a) => port.postMessage(...a)`.","Invoke methods as member expressions on the port instance itself.","Verify `port instanceof MessagePort` before use and never substitute mocks for real entangled ports."],"exampleFix":"// before\nconst send = port.postMessage;\nsend(data); // TypeError: Illegal invocation\n\n// after\nconst send = port.postMessage.bind(port);\nsend(data);","handlingStrategy":"type-guard","validationCode":"if (!(port instanceof MessagePort)) {\n  throw new TypeError(\"A real MessagePort instance is required\");\n}\nport.postMessage(data);","typeGuard":"const isMessagePort = (v) => v instanceof MessagePort;","tryCatchPattern":null,"preventionTips":["Bind methods when extracting them: `port.postMessage.bind(port)`.","Invoke MessagePort methods as member expressions (port.close(), port.start()).","Never wrap ports in Proxy or substitute mock objects for real entangled ports."],"tags":["messageport","this-binding","illegal-invocation","webidl"],"backgroundTag":"illegal-invocation","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}