{"record":{"id":"b9b37e7fe99ad3d4","repo":"AvaloniaUI/Avalonia","slug":"unable-to-access-net-memory","errorCode":null,"errorMessage":"Unable to access .NET memory","messagePattern":"Unable to access \\.NET memory","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/softwareRenderTarget.ts","lineNumber":35,"sourceCode":"\n        this.runtime = globalThis.getDotnetRuntime(0);\n    }\n\n    public putPixelData(pointer: number, length: number, width: number, height: number): void {\n        const heap8 = this.runtime?.localHeapViewU8();\n\n        let clampedBuffer: Uint8ClampedArray;\n        if (heap8?.buffer) {\n            clampedBuffer = new Uint8ClampedArray(heap8.buffer, pointer, length);\n\n            // Need to make a copy if using MT, ImageData can't consume shared arrays\n            if (this.canvas instanceof OffscreenCanvas) {\n                const dstArrayBuffer = new ArrayBuffer(clampedBuffer.byteLength);\n                const copy = new Uint8ClampedArray(dstArrayBuffer);\n                copy.set(clampedBuffer);\n                clampedBuffer = copy;\n            }\n        } else throw new Error(\"Unable to access .NET memory\");\n\n        const imageData = new ImageData(clampedBuffer, width, height);\n        (this.context).putImageData(imageData, 0, 0);\n    }\n\n    public static staticPutPixelData(target: SoftwareRenderTarget, pointer: number, length: number, width: number, height: number): void {\n        target.putPixelData(pointer, length, width, height);\n    }\n}\n","sourceCodeStart":17,"sourceCodeEnd":45,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/softwareRenderTarget.ts#L17-L45","documentation":"Thrown by SoftwareRenderTarget.putPixelData when the cached runtime's localHeapViewU8() (or its underlying ArrayBuffer) is unavailable. This view is the bridge into the .NET WASM linear memory used to copy frame pixels into an ImageData. Without it the renderer cannot read the framebuffer the managed side produced.","triggerScenarios":"putPixelData(pointer, length, width, height) is called when globalThis.getDotnetRuntime(0) returned undefined at construction time, the runtime was shut down/disposed, or localHeapViewU8() returned a value whose .buffer is falsy (detached/grown ArrayBuffer after memory growth).","commonSituations":".NET WASM runtime not fully initialized before the first render tick; runtime disposed during navigation/reload; memory was grown (heap resized) invalidating a previously captured view; running the webapp outside the real Avalonia WASM host so getDotnetRuntime is undefined.","solutions":["Defer rendering until the .NET runtime reports ready and getDotnetRuntime(0) is non-null.","Re-fetch the heap view on every putPixelData call rather than relying on a stale reference.","Stop the render loop on runtime disposal/dispose events before the next putPixelData.","Guard the entry point: skip or reschedule the frame when this.runtime is undefined instead of throwing."],"exampleFix":"// before\nconst heap8 = this.runtime?.localHeapViewU8();\nif (heap8?.buffer) { ... } else throw new Error(\"Unable to access .NET memory\");\n\n// after\nconst runtime = globalThis.getDotnetRuntime(0);\nconst heap8 = runtime?.localHeapViewU8();\nif (!heap8?.buffer) { return; /* skip frame, runtime not ready */ }","handlingStrategy":"validation","validationCode":"const runtime = globalThis.getDotnetRuntime?.(0);\nconst heap = runtime?.localHeapViewU8();\nif (!runtime || !heap?.buffer) { /* skip frame, runtime not ready */ }","typeGuard":"function hasDotnetMemory(rt: RuntimeAPI | undefined): boolean {\n  const heap = rt?.localHeapViewU8();\n  return !!heap && !!heap.buffer && heap.buffer.byteLength > 0;\n}","tryCatchPattern":"try { target.putPixelData(pointer, length, width, height); }\ncatch (e) {\n  if (e instanceof Error && e.message.includes('.NET memory')) { /* reschedule next frame */ return; }\n  throw e;\n}","preventionTips":["Start the render loop only after the .NET runtime ready signal.","Re-fetch localHeapViewU8 each frame instead of caching across memory growth.","Stop rendering on runtime dispose."],"tags":["browser","rendering","wasm","interop","typescript","dotnet-memory"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}