dotnet/runtime · error · Error

NotImplementedException ${jsType}. For more information see

Error message

NotImplementedException ${jsType}. For more information see https://aka.ms/dotnet-wasm-jsinterop

What it means

The final fallback in the GCHandle-holding branch of marshalCsObjectToCs: the value is a managed proxy (created by C#) but is neither ManagedError nor ManagedObject, so the runtime does not know how to type-tag it. jsType is included to aid diagnosis.

Source

Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts:414

                if (BuildConfiguration === "Debug" && Object.isExtensible(value)) {
                    value[proxyDebugSymbol] = `JS Object with JSHandle ${jsHandle}`;
                }
                setJsHandle(arg, jsHandle);
            } else {
                throw new Error(`JSObject proxy is not supported for ${jsType} ${value}`);
            }
        } else {
            assertNotDisposed(value);
            if (value instanceof ArraySegment) {
                throw new Error("NotImplementedException: ArraySegment. " + jsinteropDoc);
            } else if (value instanceof ManagedError) {
                setArgType(arg, MarshalerType.Exception);
                setGcHandle(arg, gcHandle);
            } else if (value instanceof ManagedObject) {
                setArgType(arg, MarshalerType.Object);
                setGcHandle(arg, gcHandle);
            } else {
                throw new Error("NotImplementedException " + jsType + ". " + jsinteropDoc);
            }
        }
    }
}

export function marshalArrayToCs(arg: JSMarshalerArgument, value: Array<any> | TypedArray | undefined | null, elementType?: MarshalerType): void {
    dotnetAssert.check(!!elementType, "Expected valid elementType parameter");
    marshalArrayToCsImpl(arg, value, elementType);
}

export function marshalArrayToCsImpl(arg: JSMarshalerArgument, value: Array<any> | TypedArray | undefined | null, elementType: MarshalerType): void {
    if (value === null || value === undefined) {
        setArgType(arg, MarshalerType.None);
    } else {
        const elementSize = arrayElementSize(elementType);
        dotnetAssert.fastCheck(elementSize != -1, () => `Element type ${elementType} not supported`);
        const length = value.length;
        const bufferLength = elementSize * length;

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Ensure the JS runtime library and the .NET WASM runtime come from the exact same build/version (re-clean and rebuild).
  2. Avoid mutating prototype chains of objects returned from C#.
  3. If you control the call, copy the data out of the proxy into a plain object before marshaling.
Defensive patterns

Strategy: validation

Validate before calling

// Hard to validate from user code; assert version integrity instead
function assertRuntimeIntact() {
    const ems: any = (globalThis as any).MONO?.ems;
    if (!ems?.DOTNET_INTEROP?.gitHash) throw new Error("runtime/loader version mismatch");
}

Try / catch

try {
    csharpApi.SendObject(proxy);
} catch (e) {
    if (String(e).includes("NotImplementedException")) {
        // copy data out of the proxy and retry with a plain object
        csharpApi.SendObject({ ...extract(proxy) });
    } else throw e;
}

Prevention

When it happens

Trigger: A future/incompatible runtime version introduces a new managed proxy kind the JS side does not recognize, or an object's internal prototype got corrupted so instanceof checks for ManagedError/ManagedObject both fail.

Common situations: Mixing build artifacts from different .NET runtime versions (loader/runtime mismatch); monkey-patching prototype chains of managed proxies; using an experimental feature whose proxy type isn't wired into the object marshaler.

Related errors


AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06). Data as JSON: /api/errors/934b8258da91f24f. Report an issue: GitHub.