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
- Build the WASM runtime with pthread support enabled if worker-side rendering is intended.
- Route rendering to the main thread (pthreadId === 0 path) when PThread is unavailable.
- Wait for runtime ready before registering canvas targets on worker threads.
- 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
- Build WASM with pthread support if worker rendering is intended.
- Detect PThread absence and route to the main-thread path.
- Wait for runtime ready before registering worker targets.
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
- Unable get pthread with id ${pthreadId}
- Unable get Worker for pthread ${pthreadId}
- Module.GL object wasn't initialized, WebGL can't be used.
- Unable to access .NET memory
- HTMLCanvasElement.getContext returned null.
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/e8c08c70db0775d9.
Report an issue: GitHub.