demo · v139

try/catch vs onerror

Before v139, a CSP-blocked worker constructor threw SecurityError at the call site — your try caught it. From v139 the constructor returns a worker that asynchronously fires an error event. Code paths that relied on the throw now silently appear to start, then fail later. Side-by-side demo, with the bridging snippet.

casepre-139 (Chromium)v139+ (spec-compliant)
blocked Worker constructorthrows SecurityErrorreturns Worker, fires error
blocked SharedWorker constructorthrows SecurityErrorreturns SharedWorker, fires error
blocked script fetch (allowed init)fires error eventfires error event
worker URL violates CSPsometimes throws, sometimes onerroralways onerror

simulated app


      

output log

recommended bridge

function makeWorker(url) {
  let w;
  try {
    w = new Worker(url);
  } catch (e) {
    // pre-139 CSP block path. Treat the same as onerror.
    return { ok: false, reason: 'sync-throw', error: e };
  }
  return new Promise((resolve) => {
    w.onerror = (e) => resolve({ ok: false, reason: 'async-error', error: e.message });
    // No error inside one frame == we have a live worker.
    queueMicrotask(() => resolve({ ok: true, worker: w }));
  });
}

see also