AvaloniaUI/Avalonia · error · Error

Unable to access .NET memory

Error message

Unable to access .NET memory

What it means

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.

Source

Thrown at src/Browser/Avalonia.Browser/webapp/modules/avalonia/rendering/softwareRenderTarget.ts:35

        this.runtime = globalThis.getDotnetRuntime(0);
    }

    public putPixelData(pointer: number, length: number, width: number, height: number): void {
        const heap8 = this.runtime?.localHeapViewU8();

        let clampedBuffer: Uint8ClampedArray;
        if (heap8?.buffer) {
            clampedBuffer = new Uint8ClampedArray(heap8.buffer, pointer, length);

            // Need to make a copy if using MT, ImageData can't consume shared arrays
            if (this.canvas instanceof OffscreenCanvas) {
                const dstArrayBuffer = new ArrayBuffer(clampedBuffer.byteLength);
                const copy = new Uint8ClampedArray(dstArrayBuffer);
                copy.set(clampedBuffer);
                clampedBuffer = copy;
            }
        } else throw new Error("Unable to access .NET memory");

        const imageData = new ImageData(clampedBuffer, width, height);
        (this.context).putImageData(imageData, 0, 0);
    }

    public static staticPutPixelData(target: SoftwareRenderTarget, pointer: number, length: number, width: number, height: number): void {
        target.putPixelData(pointer, length, width, height);
    }
}

View on GitHub (pinned to 11c5427268)

Solutions

  1. Defer rendering until the .NET runtime reports ready and getDotnetRuntime(0) is non-null.
  2. Re-fetch the heap view on every putPixelData call rather than relying on a stale reference.
  3. Stop the render loop on runtime disposal/dispose events before the next putPixelData.
  4. Guard the entry point: skip or reschedule the frame when this.runtime is undefined instead of throwing.

Example fix

// before
const heap8 = this.runtime?.localHeapViewU8();
if (heap8?.buffer) { ... } else throw new Error("Unable to access .NET memory");

// after
const runtime = globalThis.getDotnetRuntime(0);
const heap8 = runtime?.localHeapViewU8();
if (!heap8?.buffer) { return; /* skip frame, runtime not ready */ }
Defensive patterns

Strategy: validation

Validate before calling

const runtime = globalThis.getDotnetRuntime?.(0);
const heap = runtime?.localHeapViewU8();
if (!runtime || !heap?.buffer) { /* skip frame, runtime not ready */ }

Type guard

function hasDotnetMemory(rt: RuntimeAPI | undefined): boolean {
  const heap = rt?.localHeapViewU8();
  return !!heap && !!heap.buffer && heap.buffer.byteLength > 0;
}

Try / catch

try { target.putPixelData(pointer, length, width, height); }
catch (e) {
  if (e instanceof Error && e.message.includes('.NET memory')) { /* reschedule next frame */ return; }
  throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: .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.

Related errors


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