{"record":{"id":"caa10ef44bf7ca21","repo":"AvaloniaUI/Avalonia","slug":"unable-get-worker-for-pthread-pthreadid","errorCode":null,"errorMessage":"Unable get Worker for pthread ${pthreadId}","messagePattern":"Unable get Worker for pthread (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/webRenderTargetRegistry.ts","lineNumber":32,"sourceCode":"\n    static create(pthreadId: number, canvas: HTMLCanvasElement, preferredModes: BrowserRenderingMode[]): number {\n        const id = WebRenderTargetRegistry.nextId++;\n        if (pthreadId === 0) {\n            WebRenderTargetRegistry.registry[id] = {\n                canvas\n            };\n            WebRenderTargetRegistry.targets[id] = WebRenderTargetRegistry.createRenderTarget(canvas, preferredModes);\n        } else {\n            const self = globalThis as any;\n            const module = self.Module ?? self.getDotnetRuntime(0)?.Module;\n            const pthreads = module?.PThread;\n            if (pthreads == null) { throw new Error(\"Unable to access emscripten PThread api\"); }\n            const pthread = pthreads.pthreads[pthreadId];\n            if (pthread == null) { throw new Error(`Unable get pthread with id ${pthreadId}`); }\n            let worker: Worker | undefined;\n            if (pthread.postMessage != null) { worker = pthread as Worker; } else { worker = pthread.worker; }\n\n            if (worker == null) { throw new Error(`Unable get Worker for pthread ${pthreadId}`); }\n            const offscreen = canvas.transferControlToOffscreen();\n            worker.postMessage({\n                avaloniaCmd: \"registerCanvas\",\n                canvas: offscreen,\n                modes: preferredModes,\n                id\n            }, [offscreen]);\n            WebRenderTargetRegistry.registry[id] = {\n                canvas,\n                worker\n            };\n        }\n        return id;\n    }\n\n    static initializeWorker() {\n        const oldHandler = self.onmessage;\n        self.onmessage = ev => {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/webRenderTargetRegistry.ts#L14-L50","documentation":"Thrown by WebRenderTargetRegistry.create when the located pthread object exposes neither a postMessage method nor a .worker property. The code needs a Worker reference to call transferControlToOffscreen and postMessage the canvas to the thread; without a worker handle the transfer is impossible.","triggerScenarios":"pthread.postMessage is null and pthread.worker is also null/undefined. Can happen with an unexpected Emscripten PThread object shape, a partially-initialized pthread, or a version mismatch between the interop assumptions and the actual Emscripten runtime internals.","commonSituations":"Emscripten version change altering the pthread object shape; a pthread in a transitional state (allocated struct but worker not yet attached); custom/patched runtime where the worker field has a different name.","solutions":["Verify the Emscripten version matches what the interop code expects for the pthread.worker field.","Defer registration until the pthread worker is fully attached.","Fall back to main-thread (pthreadId === 0) rendering if no worker handle can be obtained.","Inspect the pthread object keys in the console to find the correct worker accessor."],"exampleFix":"// before\nif (pthread.postMessage != null) { worker = pthread as Worker; } else { worker = pthread.worker; }\nif (worker == null) throw new Error(`Unable get Worker for pthread ${pthreadId}`);\n\n// after\nconst worker = pthread.postMessage ? pthread : pthread.worker ?? pthread._worker;\nif (!worker) { /* fall back to main-thread rendering */ return WebRenderTargetRegistry.create(0, canvas, modes); }","handlingStrategy":"fallback","validationCode":"const pthread = pthreads.pthreads[pthreadId];\nconst worker = pthread?.postMessage ? pthread : pthread?.worker;\nif (!worker) { /* fall back to main-thread rendering (pthreadId 0) */ }","typeGuard":"function hasWorkerHandle(pthreadId: number): boolean {\n  const self = globalThis as any;\n  const pthreads = (self.Module ?? self.getDotnetRuntime?.(0)?.Module)?.PThread?.pthreads;\n  const p = pthreads?.[pthreadId];\n  return !!(p && (p.postMessage || p.worker));\n}","tryCatchPattern":"try { return WebRenderTargetRegistry.create(pthreadId, canvas, modes); }\ncatch (e) {\n  if (e instanceof Error && /Worker for pthread/.test(e.message)) { return WebRenderTargetRegistry.create(0, canvas, modes); }\n  throw e;\n}","preventionTips":["Verify the Emscripten version exposes pthread.worker (or pthread._worker).","Defer registration until the pthread worker is attached.","Keep a main-thread fallback when no worker handle is obtainable."],"tags":["browser","rendering","emscripten","pthread","worker","typescript"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}