Diagnosing WebAssembly Thread Failures: SharedArrayBuffer and Cross-Origin Isolation
Threaded WebAssembly fails when SharedArrayBuffer is missing. Confirm cross-origin isolation before rebuilding your module.
07 Sept 2026, 22:26 UTC

Problem: Threaded WebAssembly will not start
You build a WebAssembly module with threading enabled, but the browser reports that SharedArrayBuffer is undefined, or WebAssembly instantiation throws an operation-not-supported error. The module works in one browser but fails in another. Rebuilding with different compiler flags rarely fixes it.
Useful takeaway: threaded WebAssembly depends on SharedArrayBuffer and Atomics, which browsers expose only in a cross-origin isolated document. Before changing your toolchain, confirm that the main document receives Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp, and that document.crossOriginIsolated is true.
Cross-origin isolation is a browser security state that separates a document from cross-origin resources so it can safely use shared memory. SharedArrayBuffer is a buffer that can be shared between the main thread and Web Workers. Atomics are operations that guarantee safe reads and writes to shared memory without data races.
Recognizable condition and likely causes
| Observable condition | Likely cause | First check |
|---|---|---|
SharedArrayBuffer is undefined | Document is not cross-origin isolated, or the browser does not support it | Run document.crossOriginIsolated in DevTools |
| WebAssembly thread instantiation throws an operation-not-supported error | Shared memory is disabled because isolation headers are missing | Inspect the main document response in the Network tab |
| Works in Chrome and Firefox, fails in Safari | Safari and iOS WebKit added cross-origin isolation later; verify minimum deployment versions | Check the Safari/WebKit version against current release notes |
Headers are present but crossOriginIsolated is still false | Document is inside a cross-origin iframe, a redirect dropped headers, or an extension modified the response | Test the page directly, not inside an embed |
Ordered checks
- Reproduce in a clean browser context. Open the page in an incognito window to exclude extensions. Open DevTools and run in the console:
Expected:console.log(typeof SharedArrayBuffer); console.log(document.crossOriginIsolated);functionorobjectfor SharedArrayBuffer, andtruefor crossOriginIsolated. If either is missing, proceed to check 2. - Confirm HTTP headers on the main document. In DevTools, open the Network tab, reload, and select the HTML document request. Look for:
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp<meta>tags do not set these policies; they must be HTTP response headers. - Verify from the command line. Run in a terminal:
Where to run: any terminal with network access. Permissions: none required. Placeholder: replacecurl -I https://example.com/your-app/https://example.com/your-app/with your deployed origin. Expected checks: both headers appear in the response. Risk:curlshows server headers, but service workers or browser-specific logic can still alter what the page sees. - Test feature detection before compiling. Do not assume threads are available just because headers exist. Run:
function canUseThreads() { return ( typeof SharedArrayBuffer !== 'undefined' && typeof Atomics !== 'undefined' && document.crossOriginIsolated === true ); } - Instantiate a minimal threaded module. If feature detection passes, compile a small WebAssembly module that imports a threaded function and confirm it succeeds on each target browser. Do not generalize from one browser.
Fixes tied to findings
Missing COOP or COEP headers
Add both headers to the response for the main HTML document. Example for Express:
app.use((req, res, next) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
next();
});
Example for Nginx:add_header Cross-Origin-Opener-Policy "same-origin";
add_header Cross-Origin-Embedder-Policy "require-corp";
Place these in the server or location block that serves the HTML document. Required permission: server configuration access. Risk: COEP: require-corp blocks cross-origin images, scripts, and iframes unless they opt in with Cross-Origin-Resource-Policy headers. This can break CDN assets, ads, and third-party embeds.Cross-origin resources blocked by COEP
If a cross-origin script or image must load, add Cross-Origin-Resource-Policy: cross-origin to that resource's response, or serve it from the same origin. For credentials-free embedding, Cross-Origin-Embedder-Policy: credentialless is an alternative, but the document still needs Cross-Origin-Opener-Policy: same-origin for isolation.
Localhost is not automatically exempt
Do not skip headers during local development because you assume localhost is trusted. Browser versions and flags may still enforce isolation. Apply the same headers locally, or use a development server that serves them by default.
Unsupported browser
If a target browser lacks cross-origin isolation, you cannot enable SharedArrayBuffer through configuration. Ship a single-threaded WebAssembly build for that browser and use feature detection to select the build at load time.
Escalation criteria
- Headers are present,
document.crossOriginIsolatedis true, but WebAssembly still throws: file a browser-specific bug with a minimal reproduction; do not keep changing compiler flags. - COEP breaks required third-party iframes or ads: involve the platform team to decide whether to isolate a subset of pages, use
credentialless, or serve third-party content from the same origin. - You need threads on Safari or older WebKit versions that do not support isolation: fall back to single-threaded WASM and document the browser cutoff.
Limitations and practical verification
- Shared memory can introduce data races. Synchronize access with
Atomicsrather than plain loads and stores. Cross-Origin-Opener-Policy: same-origincan break cross-origin popups and opener relationships.- Verify the result by opening DevTools, confirming
document.crossOriginIsolatedreturnstrue, and checking that the Network tab shows both policies on the main document request. - Draft note: Safari and iOS WebKit minimum versions for cross-origin isolation should be checked against current browser release notes before publishing; this draft does not assert specific version numbers.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.