denoland/deno · error · TypeError
Illegal invocation
Error message
Illegal invocation
What it means
Deno implements `WorkerLocation` (the class of the `location` global inside Web Workers) by storing each instance's parsed URL in the module-private `workerLocationUrls` WeakMap. The prototype getter for `hash` (ext/web/12_location.js:243-251) does `WeakMapPrototypeGet(workerLocationUrls, this)` and throws `TypeError: Illegal invocation` when the lookup returns null — i.e., when the accessor runs with a receiver that is not a genuine `WorkerLocation` instance. This is Deno's version of the brand check browsers perform on WebIDL accessors.
Source
Thrown at ext/web/12_location.js:248
class WorkerLocation {
constructor(href = null, key = null) {
if (key != locationConstructorKey) {
throw new TypeError("Illegal constructor");
}
const url = new URL(href);
url.username = "";
url.password = "";
WeakMapPrototypeSet(workerLocationUrls, this, url);
}
}
ObjectDefineProperties(WorkerLocation.prototype, {
hash: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
throw new TypeError("Illegal invocation");
}
return url.hash;
},
configurable: true,
enumerable: true,
},
host: {
__proto__: null,
get() {
const url = WeakMapPrototypeGet(workerLocationUrls, this);
if (url == null) {
throw new TypeError("Illegal invocation");
}
return url.host;
},
configurable: true,
enumerable: true,
},View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Access the property on the real instance: `location.hash` (or `self.location.hash` inside the worker).
- If you extracted the getter, invoke it bound: `get.call(location)` or `Reflect.apply(get, location, [])`.
- Stop fabricating receivers — the private WeakMap rejects any object that was not constructed by Deno internals, by design.
- In generic serializer/polyfill code, read values off instances (`location.hash`) instead of re-invoking prototype accessors.
Example fix
// before const getHash = Object.getOwnPropertyDescriptor(WorkerLocation.prototype, 'hash').get; const h = getHash.call(myFakeLocation); // TypeError: Illegal invocation // after const h = location.hash; // read via the real global instance
Defensive patterns
Strategy: type-guard
Validate before calling
// Always go through the real instance from the global scope const loc = typeof location !== 'undefined' ? location : null; const hash = loc?.hash; // fine: getter invoked with this === loc // For descriptor-driven code, brand-check the receiver first: const isReal = loc != null && typeof WorkerLocation !== 'undefined' && loc instanceof WorkerLocation;
Type guard
function isWorkerLocation(obj) {
return typeof WorkerLocation !== 'undefined' && obj instanceof WorkerLocation;
} Prevention
- Invoke accessors through the real instance (location.hash), never an extracted getter
- Bind extracted getters to the owning instance: get.call(location)
- Never fake receivers with Object.create(WorkerLocation.prototype) or subclass stubs
- Avoid copying WebIDL accessor descriptors in serializers; read values off instances
When it happens
Trigger: `Object.getOwnPropertyDescriptor(WorkerLocation.prototype, 'hash').get.call(fakeObj)`, `Object.create(WorkerLocation.prototype).hash`, or any code path that invokes the `hash` accessor with a receiver other than the real `location` instance. Normal `location.hash` reads inside a worker never throw.
Common situations: Generic serializers/inspectors that walk prototypes and re-invoke accessors; duck-typing or cloning attempts with `Object.create(WorkerLocation.prototype)`; test doubles built by subclassing; deep-clone or polyfill utilities that copy property descriptors.
Related errors
- Illegal invocation
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_ARG_VALUE
- Output length ${outputLength} is invalid for ${algoLower}, w
- ERR_CRYPTO_HASH_FINALIZED
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/7087dd9d0cf51337.
Report an issue: GitHub.