denoland/deno · error · TypeError
Illegal constructor
Error message
Illegal constructor
What it means
Deno.PermissionStatus is exposed as a class but is not constructible: its constructor in runtime/js/10_permissions.js requires a private illegalConstructorKey symbol that only the permissions machinery holds. `new Deno.PermissionStatus()` throws TypeError('Illegal constructor'), matching the web-platform pattern where status objects are produced solely by query/request calls.
Source
Thrown at runtime/js/10_permissions.js:100
onchange = null;
/** @returns {Deno.PermissionState} */
get state() {
return this.#status.state;
}
/** @returns {boolean} */
get partial() {
return this.#status.partial;
}
/**
* @param {{ state: Deno.PermissionState, partial: boolean }} status
* @param {unknown} key
*/
constructor(status = null, key = null) {
if (key != illegalConstructorKey) {
throw new TypeError("Illegal constructor");
}
super();
this.#status = status;
}
/**
* @param {Event} event
* @returns {boolean}
*/
dispatchEvent(event) {
let dispatched = super.dispatchEvent(event);
if (dispatched && this.onchange) {
FunctionPrototypeCall(this.onchange, this, event);
dispatched = !event.defaultPrevented;
}
return dispatched;
}
View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Obtain real instances from the factory API: `const status = await Deno.permissions.query({ name: 'read' })` (also querySync and request)
- In tests, stub at the API level — replace Deno.permissions.query — instead of constructing status objects
- If you only need the shape, define a plain type: `type StatusLike = { state: Deno.PermissionState; partial: boolean }`
Example fix
// before
const status = new Deno.PermissionStatus(); // TypeError: Illegal constructor
// after
const status = await Deno.permissions.query({ name: 'read' });
console.log(status.state, status.partial); Defensive patterns
Strategy: validation
Type guard
const isPermissionStatus = (v) => v instanceof Deno.PermissionStatus;
Prevention
- Treat Deno.PermissionStatus as factory-produced — only Deno.permissions.query/querySync/request may create it
- In tests, stub Deno.permissions.query instead of fabricating status objects
- Do not subclass web-platform classes with illegal constructors; compose plain types instead
When it happens
Trigger: `new Deno.PermissionStatus()`; `class X extends Deno.PermissionStatus { constructor() { super(); } }` (super() is invoked without the key); test code attempting to fabricate a status object.
Common situations: Unit tests that want a fixed { state, partial } shape without stubbing the API; code ported from environments where permission status is a plain data object.
Related errors
- The provided value "${desc?.name}" is not a valid permission
- Expected the second argument to assertSnapshot() to be an op
- Snapshot serializer must return a string
- Invalid port: '${maybePort}'
- Invalid port: ${maybePort}
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/14ce21d412564616.
Report an issue: GitHub.