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

  1. Use exactly one of: read, write, net, env, sys, run, ffi, import — with the per-name field (path, host, command, variable, kind) where applicable
  2. Validate the descriptor with a type guard before calling query (see defense)
  3. If the name comes from config, check it against a const array and fail early with your own error
  4. 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

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


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/76a24e668738c586. Report an issue: GitHub.