{"record":{"id":"42ed0d3e1059cafd","repo":"dotnet/runtime","slug":"notimplementedexception-elementtype-jsintero","errorCode":null,"errorMessage":"NotImplementedException ${elementType}. ${jsinteropDoc}","messagePattern":"NotImplementedException (.+?)\\. (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts","lineNumber":470,"sourceCode":"        }\n    } else if (elementType == MarshalerType.Byte) {\n        const bufferOffset = fixupPointer(bufferPtr, 0);\n        const sourceView = dotnetApi.localHeapViewU8().subarray(bufferOffset, bufferOffset + length);\n        result = sourceView.slice();//copy\n    } else if (elementType == MarshalerType.Int32) {\n        const bufferOffset = fixupPointer(bufferPtr, 2);\n        const sourceView = dotnetApi.localHeapViewI32().subarray(bufferOffset, bufferOffset + length);\n        result = sourceView.slice();//copy\n    } else if (elementType == MarshalerType.Double) {\n        const bufferOffset = fixupPointer(bufferPtr, 3);\n        const sourceView = dotnetApi.localHeapViewF64().subarray(bufferOffset, bufferOffset + length);\n        result = sourceView.slice();//copy\n    } else if (elementType == MarshalerType.Single) {\n        const bufferOffset = fixupPointer(bufferPtr, 2);\n        const sourceView = dotnetApi.localHeapViewF32().subarray(bufferOffset, bufferOffset + length);\n        result = sourceView.slice();//copy\n    } else {\n        throw new Error(`NotImplementedException ${elementType}. ${jsinteropDoc}`);\n    }\n    Module._free(<any>bufferPtr);\n    return result;\n}\n\nfunction _marshalSpanToJs(arg: JSMarshalerArgument, elementType?: MarshalerType): Span {\n    dotnetAssert.check(!!elementType, \"Expected valid elementType parameter\");\n\n    const bufferPtr = getArgIntptr(arg);\n    const length = getArgLength(arg);\n    let result: Span | null = null;\n    if (elementType == MarshalerType.Byte) {\n        result = new Span(<any>bufferPtr, length, MemoryViewType.Byte);\n    } else if (elementType == MarshalerType.Int32) {\n        result = new Span(<any>bufferPtr, length, MemoryViewType.Int32);\n    } else if (elementType == MarshalerType.Double) {\n        result = new Span(<any>bufferPtr, length, MemoryViewType.Double);\n    } else if (elementType == MarshalerType.Single) {","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts#L452-L488","documentation":"Thrown by _marshalArrayToJs_impl at the final else branch when marshaling a C# array back to JS whose elementType is not String/Object/JSObject/Byte/Int32/Double/Single. The reverse direction of marshalArrayToCsImpl: only those seven element kinds have a buffer-view materializer, so anything else is rejected rather than producing garbage.","triggerScenarios":"A [JSExport] (or [JSInvokable] from the JS perspective) C# method returns an array of an unsupported element type (Int16[], char[], long[], enum[], Nullable<T>[], etc.) and the marshaler tries to convert the returned buffer into a JS array. Hit at marshal-to-js.ts:470.","commonSituations":"Returning short[]/char[]/nint[] from a C# export and reading the result in JS. Using an enum-typed array. Runtime/loader version skew where the C# assembly was rebuilt with a new return type but the JS marshaler was not.","solutions":["Change the C# return element type to a supported one: byte, int, double, float, string, object, or JSObject.","If you must return 16-bit values, return int[] and downcast on the JS side.","Rebuild and redeploy the runtime + assemblies together so the element-type table is consistent."],"exampleFix":"// before (C#)\n[JSExport] public static short[] GetIds() => new short[]{1,2,3}; // JS throws NotImplementedException Int16\n\n// after (C#)\n[JSExport] public static int[] GetIds() => new int[]{1,2,3}; // Int32 supported","handlingStrategy":"validation","validationCode":"const SUPPORTED = new Set(['Byte','Int32','Double','Single','String','Object','JSObject']);\n\n// Validate at the C# design level before exposing the export:\n//   [JSExport] static int[] Get() => ...   // OK\n//   [JSExport] static short[] Get() => ... // will throw - avoid\nif (!SUPPORTED.has(returnedElementType)) {\n  throw new Error('Refusing to expose an export returning an unsupported array element type');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const arr = await csharpExport();\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('NotImplementedException ')) {\n    // The C# export returned an array of an unsupported element type.\n    throw new TypeError('C# export must return byte[]/int[]/double[]/float[]/string[]/object[]/JSObject[]', { cause: e });\n  }\n  throw e;\n}","preventionTips":["Restrict [JSExport] return array element types to byte/int/double/float/string/object/JSObject.","Add a unit test that exercises each export's return path on the JS side.","Rebuild runtime + assemblies together after changing a return type."],"tags":["dotnet-wasm","jsinterop","marshaling","typescript","arrays","not-implemented"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}