dotnet/runtime · error · Error

NotImplementedException ${js_type}. For more information see

Error message

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

What it means

The final else of the managed-proxy branch in marshal_cs_object_to_cs: the value carries a js_owned_gc_handle_symbol (so it is some kind of managed object proxy) but it is neither a ManagedError nor a ManagedObject, so the object marshaler does not know how to map it back. Typically indicates a version/runtime mismatch or a custom wrapper masquerading as a managed proxy.

Source

Thrown at src/mono/browser/runtime/marshal-to-cs.ts:443

                if (BuildConfiguration === "Debug" && Object.isExtensible(value)) {
                    value[proxy_debug_symbol] = `JS Object with JSHandle ${js_handle}`;
                }
                set_js_handle(arg, js_handle);
            } else {
                throw new Error(`JSObject proxy is not supported for ${js_type} ${value}`);
            }
        } else {
            assert_not_disposed(value);
            if (value instanceof ArraySegment) {
                throw new Error("NotImplementedException: ArraySegment. " + jsinteropDoc);
            } else if (value instanceof ManagedError) {
                set_arg_type(arg, MarshalerType.Exception);
                set_gc_handle(arg, gc_handle);
            } else if (value instanceof ManagedObject) {
                set_arg_type(arg, MarshalerType.Object);
                set_gc_handle(arg, gc_handle);
            } else {
                throw new Error("NotImplementedException " + js_type + ". " + jsinteropDoc);
            }
        }
    }
}

export function marshal_array_to_cs (arg: JSMarshalerArgument, value: Array<any> | TypedArray | undefined | null, element_type?: MarshalerType): void {
    mono_assert(!!element_type, "Expected valid element_type parameter");
    marshal_array_to_cs_impl(arg, value, element_type);
}

export function marshal_array_to_cs_impl (arg: JSMarshalerArgument, value: Array<any> | TypedArray | undefined | null, element_type: MarshalerType): void {
    if (value === null || value === undefined) {
        set_arg_type(arg, MarshalerType.None);
    } else {
        const element_size = array_element_size(element_type);
        mono_assert(element_size != -1, () => `Element type ${element_type} not supported`);
        const length = value.length;
        const buffer_length = element_size * length;

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Ensure the JS and C# runtime versions match exactly (rebuild/redeploy both sides).
  2. Do not attach or copy internal proxy symbols onto custom objects.
  3. If holding a stale proxy from a previous runtime init, discard it and obtain a fresh reference.

Example fix

// before
// reusing a managed proxy object captured before a runtime restart
dotnet.jsExports.Take(staleManagedObjectProxy); // throws
// after
// re-fetch the managed object from the current runtime instance
Defensive patterns

Strategy: validation

Validate before calling

// Treat any object carrying the internal managed-proxy symbol as runtime-bound; do not reuse across inits.
if (value && typeof value === 'object' && Object.getOwnPropertySymbols(value).some(s => String(s).includes('gc_handle'))) {
  console.warn('Passing a possible stale managed proxy; ensure runtime versions match and references are fresh.');
}

Prevention

When it happens

Trigger: Passing an object that has the managed-proxy symbol but is not a recognized ManagedObject/ManagedError instance to an object-typed C# parameter.

Common situations: Mixing runtime versions where proxy class identity changed; a third-party wrapper that copies internal proxy symbols onto unrelated objects; stale references from a previous runtime instance.

Related errors


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