denoland/deno · error · DOMException

SyntaxError

SyntaxError

Error message

Failed to parse URL: ${scriptUrl}

What it means

importScripts parses each argument with `new URL(scriptUrl, baseUrl)` against the worker's location; a parse failure throws DOMException(`Failed to parse URL: ${scriptUrl}`, 'SyntaxError') in runtime/js/99_main.js. The check is purely syntactic — it validates that the argument is an absolute URL or resolvable relative URL per the WHATWG parser; reachability is only tested later by op_worker_sync_fetch.

Source

Thrown at runtime/js/99_main.js:400

      op_worker_maybe_wait_for_debugger();
      dispatchWorkerMessage(syncData);
    }
  }
}

let loadedMainWorkerScript = false;

function importScripts(...urls) {
  if (op_worker_get_type() !== "classic") {
    throw new TypeError("Cannot import scripts in a module worker");
  }

  const baseUrl = location.getLocationHref();
  const parsedUrls = ArrayPrototypeMap(urls, (scriptUrl) => {
    try {
      return new url.URL(scriptUrl, baseUrl ?? undefined).href;
    } catch {
      throw new DOMException(
        `Failed to parse URL: ${scriptUrl}`,
        "SyntaxError",
      );
    }
  });

  // A classic worker's main script has looser MIME type checks than any
  // imported scripts, so we use `loadedMainWorkerScript` to distinguish them.
  // TODO(andreubotella) Refactor worker creation so the main script isn't
  // loaded with `importScripts()`.
  const scripts = op_worker_sync_fetch(
    parsedUrls,
    !loadedMainWorkerScript,
  );
  loadedMainWorkerScript = true;

  for (let i = 0; i < scripts.length; ++i) {
    const { url, script } = scripts[i];

View on GitHub (pinned to a961cdec3b)

Solutions

  1. Pass a well-formed absolute or resolvable-relative URL, percent-encoded where needed
  2. Pre-validate with `URL.canParse(scriptUrl, baseUrl)` (or a try/catch around new URL) before calling importScripts
  3. Build URLs programmatically with `new URL(path, base).href` and pass the result

Example fix

// before
importScripts(base + '?file=' + fileName + '&mode=' + mode);

// after
importScripts(
  new URL(
    `?file=${encodeURIComponent(fileName)}&mode=${encodeURIComponent(mode)}`,
    base,
  ).href,
);
Defensive patterns

Strategy: validation

Validate before calling

const base = typeof location !== 'undefined' ? location.href : undefined;
if (!URL.canParse(scriptUrl, base)) {
  throw new Error(`importScripts argument is not a parseable URL: ${scriptUrl}`);
}
importScripts(scriptUrl);

Try / catch

try {
  importScripts(u);
} catch (e) {
  if (e instanceof DOMException && e.name === 'SyntaxError') {
    // fix the URL string (encode components) and retry
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: `importScripts('not a url ::')`; strings with unencoded spaces or query fragments; Windows paths like 'C:\lib.js'; a relative URL when the worker has no base href (baseUrl null).

Common situations: Building script URLs by string concatenation without encodeURIComponent; passing file paths from configuration; porting scripts that relied on eval-style path resolution.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of denoland/deno@a961cdec3b (2026-08-20). Data as JSON: /api/errors/2186320054f79dbe. Report an issue: GitHub.