denoland/deno · error · DOMException

NotSupportedError

NotSupportedError

Error message

'name' must not start with '-'

What it means

The Web Locks API reserves lock names beginning with a hyphen ('-') for internal use, so LockManager.request rejects them with a DOMException named NotSupportedError, thrown from ext/web/locks.js after option conversion but before acquiring anything. The check uses startsWith on the raw name string. Nothing was locked when this throws.

Solutions

  1. Rename the lock so it does not start with '-', e.g. 'mylock' or 'app:mylock'.
  2. If names derive from user input, sanitize: name.replace(/^-+/, "").
  3. Validate generated names with a check like name.startsWith('-') before calling request.
  4. Pick a namespace separator that cannot appear at position 0, such as ':' or '__'.

Example fix

// before
navigator.locks.request("-job:" + id, cb);

// after
navigator.locks.request("job:" + id, cb);
Defensive patterns

Strategy: validation

Validate before calling

function lockName(name) {
  const n = name.replace(/^-+/, "");
  if (n.startsWith("-")) throw new Error(`invalid lock name: ${name}`);
  return n;
}
navigator.locks.request(lockName(raw), cb);

Type guard

function isValidLockName(name) {
  return typeof name === "string" && name.length > 0 && !name.startsWith("-");
}

Try / catch

try { await navigator.locks.request(name, cb); } catch (e) { if (e.name === "NotSupportedError" && e.message.includes("'-'")) await navigator.locks.request(name.replace(/^-+/, ""), cb); else throw e; }

Prevention

When it happens

Trigger: navigator.locks.request("-mylock", cb); names built from user input or generated IDs that start with '-'; prefixing names with '-' as a namespace convention ('-app:resource').

Common situations: Auto-generated lock keys from slugs or CLI-style flags ('--job-42'); copying a naming scheme from a queue/redis library where '-' prefixes are allowed; concatenating '-' separators after an empty first segment, producing a leading '-'.

Related errors


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

Appendix: source

Thrown at ext/web/locks.js:124

    if (arguments.length === 2) {
      options = {};
      callback = optionsOrCallback;
    } else {
      options = optionsOrCallback;
    }

    if (typeof callback !== "function") {
      throw new TypeError("callback must be a function");
    }

    options = webidl.converters.LockOptions(
      options,
      prefix,
      "Argument 2",
    );

    if (StringPrototypeStartsWith(name, "-")) {
      throw new DOMException(
        "'name' must not start with '-'",
        "NotSupportedError",
      );
    }
    if (options.steal && options.ifAvailable) {
      throw new DOMException(
        "'steal' and 'ifAvailable' are exclusive",
        "NotSupportedError",
      );
    }
    if (options.steal && options.mode !== "exclusive") {
      throw new DOMException(
        "'mode' must be 'exclusive' if 'steal' is specified",
        "NotSupportedError",
      );
    }
    if (options.signal && (options.steal || options.ifAvailable)) {
      throw new DOMException(

View on GitHub (pinned to 9ad36f7a2c)