{"record":{"id":"3f3747874adcb224","repo":"dotnet/runtime","slug":"notimplementedexception-jstype-jsinteropdoc","errorCode":null,"errorMessage":"NotImplementedException ${jsType}. ${jsinteropDoc}","messagePattern":"NotImplementedException (.+?)\\. (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts","lineNumber":414,"sourceCode":"                if (BuildConfiguration === \"Debug\" && Object.isExtensible(value)) {\n                    value[proxyDebugSymbol] = `JS Object with JSHandle ${jsHandle}`;\n                }\n                setJsHandle(arg, jsHandle);\n            } else {\n                throw new Error(`JSObject proxy is not supported for ${jsType} ${value}`);\n            }\n        } else {\n            assertNotDisposed(value);\n            if (value instanceof ArraySegment) {\n                throw new Error(\"NotImplementedException: ArraySegment. \" + jsinteropDoc);\n            } else if (value instanceof ManagedError) {\n                setArgType(arg, MarshalerType.Exception);\n                setGcHandle(arg, gcHandle);\n            } else if (value instanceof ManagedObject) {\n                setArgType(arg, MarshalerType.Object);\n                setGcHandle(arg, gcHandle);\n            } else {\n                throw new Error(\"NotImplementedException \" + jsType + \". \" + jsinteropDoc);\n            }\n        }\n    }\n}\n\nexport function marshalArrayToCs(arg: JSMarshalerArgument, value: Array<any> | TypedArray | undefined | null, elementType?: MarshalerType): void {\n    dotnetAssert.check(!!elementType, \"Expected valid elementType parameter\");\n    marshalArrayToCsImpl(arg, value, elementType);\n}\n\nexport function marshalArrayToCsImpl(arg: JSMarshalerArgument, value: Array<any> | TypedArray | undefined | null, elementType: MarshalerType): void {\n    if (value === null || value === undefined) {\n        setArgType(arg, MarshalerType.None);\n    } else {\n        const elementSize = arrayElementSize(elementType);\n        dotnetAssert.fastCheck(elementSize != -1, () => `Element type ${elementType} not supported`);\n        const length = value.length;\n        const bufferLength = elementSize * length;","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts#L396-L432","documentation":"Thrown by marshalCsObjectToCs when a value carries the jsOwnedGcHandleSymbol (so it is treated as a C#-roundtripped object) but its runtime type is neither ManagedError, ManagedObject, nor ArraySegment. The .NET JS interop marshaler only knows how to send these specific managed proxy shapes back to C#, so any other prototype that happens to carry the gcHandle symbol is rejected as not implemented. The message includes the JS typeof string and a link to the jsinterop docs.","triggerScenarios":"Passing a value to a C# [JSExport] argument where the value has the jsOwnedGcHandleSymbol property but is an instance of a custom/extension class rather than ManagedObject/ManagedError/ArraySegment (e.g. an object that wrapped or cloned a managed proxy, or a ManagedObject subclass the marshaler does not recognize). Reached whenever marshalCsObjectToCs takes the gcHandle !== undefined branch at marshal-to-cs.ts:403 and falls through all instanceof checks to line 414.","commonSituations":"Manually copying properties off a ManagedObject onto a plain object (which then inherits/retains the symbol), subclassing ManagedObject in user JS interop code, passing a stale proxy whose prototype was swapped, or using reflection-like wrappers around C# objects. Also seen when a NuGet dotnet wasm build is mismatched with the JS runtime so proxy class identity checks (instanceof ManagedObject) fail.","solutions":["Pass the original ManagedObject/ManagedError instance directly instead of a wrapper or copy; do not transplant the gcHandle symbol onto other objects.","If you subclassed ManagedObject, ensure instanceof checks still hold (do not override Symbol.hasInstance / prototype chains) or unwrap to the base instance before the interop call.","Rebuild and redeploy the dotnet wasm runtime and JS loader from the same source/commit so the ManagedObject class identity used by instanceof matches at runtime.","Audit the call site with a debugger break at marshal-to-cs.ts:414 to confirm the value's prototype and that value[jsOwnedGcHandleSymbol] is genuinely expected."],"exampleFix":"// before\nconst wrapped = Object.assign({}, csharpObject); // carries jsOwnedGcHandleSymbol via copy?\nexportToCSharp(wrapped); // throws NotImplementedException object.\n\n// after\nexportToCSharp(csharpObject); // pass the original ManagedObject instance","handlingStrategy":"type-guard","validationCode":"import { ManagedObject, ManagedError, ArraySegment } from 'System.Runtime.InteropServices.JavaScript.Native/interop/core';\n\nfunction isMarshalableCsObject(v: unknown): boolean {\n  if (v === null || v === undefined) return true; // None path\n  if (!(typeof v === 'object')) return false;\n  const hasGc = (v as any)[jsOwnedGcHandleSymbol] !== undefined;\n  if (!hasGc) return true; // non-gcHandle branch handles primitives/arrays/etc.\n  return v instanceof ManagedObject || v instanceof ManagedError || v instanceof ArraySegment;\n}\n\nif (!isMarshalableCsObject(arg)) throw new TypeError('arg is not a marshalable managed proxy');","typeGuard":"function isManagedObjectLike(v: unknown): v is ManagedObject | ManagedError | ArraySegment {\n  return v instanceof ManagedObject || v instanceof ManagedError || v instanceof ArraySegment;\n}","tryCatchPattern":"try {\n  exportToCSharp(maybeProxy);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('NotImplementedException ')) {\n    throw new TypeError('Passed a non-managed object to C# interop; unwrap to the original ManagedObject.', { cause: e });\n  }\n  throw e;\n}","preventionTips":["Never copy/transplant the jsOwnedGcHandleSymbol onto other objects.","Pass ManagedObject/ManagedError/ArraySegment instances directly, not wrappers.","Keep the dotnet wasm runtime and the JS loader on the same build so instanceof checks hold."],"tags":["dotnet-wasm","jsinterop","marshaling","typescript","not-implemented"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}