denoland/deno · error · TypeError
The provided value "${desc?.name}" is not a valid permission
Error message
The provided value "${desc?.name}" is not a valid permission name What it means
Deno.permissions.query/querySync validate the descriptor before touching the permission backend: it must be a non-null object whose `name` is one of read, write, net, env, sys, run, ffi, import (the permissionNames list in runtime/js/10_permissions.js). Anything else throws TypeError(`The provided value "${desc?.name}" is not a valid permission name`) — with 'undefined' interpolated when the argument is missing or not an object. The async query() surfaces this as a rejected promise.
Source
Thrown at runtime/js/10_permissions.js:216
class Permissions {
constructor(key = null) {
if (key != illegalConstructorKey) {
throw new TypeError("Illegal constructor");
}
}
query(desc) {
try {
return PromiseResolve(this.querySync(desc));
} catch (error) {
return PromiseReject(error);
}
}
querySync(desc) {
if (!isValidDescriptor(desc)) {
throw new TypeError(
`The provided value "${desc?.name}" is not a valid permission name`,
);
}
formDescriptor(desc);
const status = opQuery(desc);
return cache(desc, status);
}
revoke(desc) {
try {
return PromiseResolve(this.revokeSync(desc));
} catch (error) {
return PromiseReject(error);
}
}
View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Use exactly one of: read, write, net, env, sys, run, ffi, import — with the per-name field (path, host, command, variable, kind) where applicable
- Validate the descriptor with a type guard before calling query (see defense)
- If the name comes from config, check it against a const array and fail early with your own error
- Remember the async variant rejects rather than throwing synchronously — attach .catch while debugging
Example fix
// before
await Deno.permissions.query({ name: 'fs', path: '/tmp' });
// after
await Deno.permissions.query({ name: 'read', path: '/tmp' }); Defensive patterns
Strategy: type-guard
Validate before calling
const PERMISSION_NAMES = ['read', 'write', 'net', 'env', 'sys', 'run', 'ffi', 'import'];
function isPermissionDescriptor(d) {
return typeof d === 'object' && d !== null &&
PERMISSION_NAMES.includes(d.name);
}
if (!isPermissionDescriptor(desc)) {
throw new TypeError(`bad permission descriptor: ${JSON.stringify(desc)}`);
}
const status = await Deno.permissions.query(desc); Type guard
function isPermissionDescriptor(d) {
return typeof d === 'object' && d !== null &&
['read', 'write', 'net', 'env', 'sys', 'run', 'ffi', 'import'].includes(d.name);
} Try / catch
Deno.permissions.query(desc).catch((e) => {
if (e instanceof TypeError && e.message.includes('not a valid permission name')) {
// descriptor is malformed — fix name and retry with user feedback
} else {
throw e;
}
}); Prevention
- Derive descriptors from a typed const so the name cannot drift
- Match CLI flag names: --allow-read maps to name 'read', not 'allow-read' or 'fs'
- Remember the async APIs reject (no synchronous throw) — attach .catch during development
When it happens
Trigger: `Deno.permissions.query({ name: 'fs' })` (Node-style naming); typos like 'reads' or 'network'; `Deno.permissions.query('read')` (a string, not an object); calling with no argument at all.
Common situations: Porting Node scripts that reason about fs/net permissions; building descriptors dynamically from config; expecting hyphenated CLI flag names (--allow-read) instead of the bare name 'read'.
Related errors
- The provided value "${desc?.name}" is not a valid permission
- Invalid port: '${maybePort}'
- Illegal constructor
- ${prefix}Linter plugin name must only contain lowercase lett
- ${prefix}Linter plugin name must start and end with a lowerc
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/76a24e668738c586.
Report an issue: GitHub.