AvaloniaUI/Avalonia · error · Error

Unable to access emscripten PThread api

Error message

Unable to access emscripten PThread api

What it means

Thrown by WebRenderTargetRegistry.create when rendering on a worker thread (pthreadId != 0) and the Emscripten Module.PThread API cannot be found. PThread is required because the canvas must be transferred to the owning pthread worker as an OffscreenCanvas via postMessage.

Source

Thrown at src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/webRenderTargetRegistry.ts:26

    private static registry: { [id: number]: ({
        canvas: HTMLCanvasElement;
        worker?: Worker;
    }); } = {};

    private static nextId = 1;

    static create(pthreadId: number, canvas: HTMLCanvasElement, preferredModes: BrowserRenderingMode[]): number {
        const id = WebRenderTargetRegistry.nextId++;
        if (pthreadId === 0) {
            WebRenderTargetRegistry.registry[id] = {
                canvas
            };
            WebRenderTargetRegistry.targets[id] = WebRenderTargetRegistry.createRenderTarget(canvas, preferredModes);
        } else {
            const self = globalThis as any;
            const module = self.Module ?? self.getDotnetRuntime(0)?.Module;
            const pthreads = module?.PThread;
            if (pthreads == null) { throw new Error("Unable to access emscripten PThread api"); }
            const pthread = pthreads.pthreads[pthreadId];
            if (pthread == null) { throw new Error(`Unable get pthread with id ${pthreadId}`); }
            let worker: Worker | undefined;
            if (pthread.postMessage != null) { worker = pthread as Worker; } else { worker = pthread.worker; }

            if (worker == null) { throw new Error(`Unable get Worker for pthread ${pthreadId}`); }
            const offscreen = canvas.transferControlToOffscreen();
            worker.postMessage({
                avaloniaCmd: "registerCanvas",
                canvas: offscreen,
                modes: preferredModes,
                id
            }, [offscreen]);
            WebRenderTargetRegistry.registry[id] = {
                canvas,
                worker
            };
        }

View on GitHub (pinned to 11c5427268)

Solutions

  1. Build the WASM runtime with pthread support enabled if worker-side rendering is intended.
  2. Route rendering to the main thread (pthreadId === 0 path) when PThread is unavailable.
  3. Wait for runtime ready before registering canvas targets on worker threads.
  4. Verify Module.PThread is present in the browser console at the time of the call.

Example fix

// before
WebRenderTargetRegistry.create(pthreadId, canvas, [BrowserRenderingMode.WebGL2]);

// after
const hasPThreads = globalThis.Module?.PThread ?? globalThis.getDotnetRuntime(0)?.Module?.PThread;
const effectivePthread = hasPThreads ? pthreadId : 0;
WebRenderTargetRegistry.create(effectivePthread, canvas, [BrowserRenderingMode.WebGL2]);
Defensive patterns

Strategy: validation

Validate before calling

const self = globalThis as any;
const module = self.Module ?? self.getDotnetRuntime?.(0)?.Module;
const hasPThreads = !!module?.PThread;
const effectivePthread = hasPThreads ? pthreadId : 0;

Type guard

function hasPThreadApi(): boolean {
  const self = globalThis as any;
  const m = self.Module ?? self.getDotnetRuntime?.(0)?.Module;
  return !!m?.PThread;
}

Try / catch

try { return WebRenderTargetRegistry.create(pthreadId, canvas, modes); }
catch (e) {
  if (e instanceof Error && e.message.includes('PThread')) { return WebRenderTargetRegistry.create(0, canvas, modes); }
  throw e;
}

Prevention

When it happens

Trigger: WebRenderTargetRegistry.create(pthreadId, canvas, modes) with a non-zero pthreadId, while globalThis.Module is undefined and getDotnetRuntime(0)?.Module is also missing PThread. Happens when the WASM build was compiled without pthreads support (-pthread) or the runtime is not yet initialized.

Common situations: Avalonia WASM build compiled without ENABLE_PTHREADS; runtime not fully booted when a worker-thread render target is requested; running outside the real Avalonia host where Module is absent; mismatched build expecting worker rendering but the artifact lacks pthread support.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/e8c08c70db0775d9. Report an issue: GitHub.