# How enabling cross-origin isolation silently broke our multi-threaded WASM image compressor
A production postmortem. We shipped browser-side image compression (Rust → WASM + WebGPU), turned on cross-origin isolation for speed, and watched every format crash with compression worker crashed . Here's the root cause and the fix. The setup We built an image compressor that runs 100% in the browser — Rust compiled to WASM for the codec work, WebGPU for the heavy ML passes (background removal,…
In a recent production postmortem, a team discovered that enabling cross-origin isolation (COI) unintentionally broke their multi-threaded WASM image compressor. The compressor, built with Rust compiled to WASM for codec work and WebGPU for heavy ML passes, was designed to run entirely in the browser with no user uploads, preserving privacy.
The team relied on shared memory and atomics for multi-threaded code paths, which required crossOriginIsolated to be enabled. To achieve this, they served the document with Cross-Origin-Embedder-Policy: require-corp and Cross-Origin-Opener-Policy: same-origin, which turned on COI and unlocked SharedArrayBuffer, allowing the multi-threaded builds to spawn workers.
The incident occurred after flipping COEP to require-corp in production, causing every image format to crash with the message "compression worker crashed." The bug was specific to real cross-origin isolation; local development without COEP and staging without the header were unaffected, causing the issue to hide until it hit production traffic.
The root cause was that nested workers, which the multi-threaded WASM packages spun up to parallelize the codec, were blocked by the COEP and CORP headers. The browser treated the spawned worker script as a cross-origin response without the correct CORP header, leading to worker initialization failure and the "compression worker crashed" error.
The team identified the issue as a perfect deadlock between the two headers they set themselves. The fix involved decoupling COI availability from the use of threads, keeping the single-threaded path as the default, and implementing self-healing on worker crashes. They removed the automatic enable of *-threaded packages based on crossOriginIsolated presence, instead opting for an explicit opt-in using the Turbo toggle.
They also ensured that the threaded package only loaded when explicitly enabled and the environment permitted it. Additionally, they added a self-heal mechanism in the worker pool, catching dead workers and retrying on the safe path to prevent a hard crash. This fix addressed the issue across all image formats, including JPG, PNG, WebP, and AVIF.
The takeaway from this incident is the double-edged nature of COI. While it unlocks speed and tightens loading policies, any code that spawns workers or sub-resources must satisfy COEP and CORP to avoid silent failure. Environment detection should not auto-enable features; instead, they should be gated on intent and verified against the environment.
Testing under real COI conditions is crucial, as COI is false on localhost and most staging setups. The team also recommends standing up a COEP-serving preview for testing and implementing a self-heal mechanism in their worker pool. They added a capability probe to their loader, ensuring that the threaded package boots successfully before using it, and logged which package eventually booted to provide visibility into any COEP blocks.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.