dotnet/runtime · error · Error
NotImplementedException ${elementType}. ${jsinteropDoc}
Error message
NotImplementedException ${elementType}. ${jsinteropDoc} What it means
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.
Source
Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts:470
}
} else if (elementType == MarshalerType.Byte) {
const bufferOffset = fixupPointer(bufferPtr, 0);
const sourceView = dotnetApi.localHeapViewU8().subarray(bufferOffset, bufferOffset + length);
result = sourceView.slice();//copy
} else if (elementType == MarshalerType.Int32) {
const bufferOffset = fixupPointer(bufferPtr, 2);
const sourceView = dotnetApi.localHeapViewI32().subarray(bufferOffset, bufferOffset + length);
result = sourceView.slice();//copy
} else if (elementType == MarshalerType.Double) {
const bufferOffset = fixupPointer(bufferPtr, 3);
const sourceView = dotnetApi.localHeapViewF64().subarray(bufferOffset, bufferOffset + length);
result = sourceView.slice();//copy
} else if (elementType == MarshalerType.Single) {
const bufferOffset = fixupPointer(bufferPtr, 2);
const sourceView = dotnetApi.localHeapViewF32().subarray(bufferOffset, bufferOffset + length);
result = sourceView.slice();//copy
} else {
throw new Error(`NotImplementedException ${elementType}. ${jsinteropDoc}`);
}
Module._free(<any>bufferPtr);
return result;
}
function _marshalSpanToJs(arg: JSMarshalerArgument, elementType?: MarshalerType): Span {
dotnetAssert.check(!!elementType, "Expected valid elementType parameter");
const bufferPtr = getArgIntptr(arg);
const length = getArgLength(arg);
let result: Span | null = null;
if (elementType == MarshalerType.Byte) {
result = new Span(<any>bufferPtr, length, MemoryViewType.Byte);
} else if (elementType == MarshalerType.Int32) {
result = new Span(<any>bufferPtr, length, MemoryViewType.Int32);
} else if (elementType == MarshalerType.Double) {
result = new Span(<any>bufferPtr, length, MemoryViewType.Double);
} else if (elementType == MarshalerType.Single) {View on GitHub (pinned to 60108ba66e)
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.
Example fix
// before (C#)
[JSExport] public static short[] GetIds() => new short[]{1,2,3}; // JS throws NotImplementedException Int16
// after (C#)
[JSExport] public static int[] GetIds() => new int[]{1,2,3}; // Int32 supported Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED = new Set(['Byte','Int32','Double','Single','String','Object','JSObject']);
// Validate at the C# design level before exposing the export:
// [JSExport] static int[] Get() => ... // OK
// [JSExport] static short[] Get() => ... // will throw - avoid
if (!SUPPORTED.has(returnedElementType)) {
throw new Error('Refusing to expose an export returning an unsupported array element type');
} Try / catch
try {
const arr = await csharpExport();
} catch (e) {
if (e instanceof Error && e.message.startsWith('NotImplementedException ')) {
// The C# export returned an array of an unsupported element type.
throw new TypeError('C# export must return byte[]/int[]/double[]/float[]/string[]/object[]/JSObject[]', { cause: e });
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- not implemented
- NotImplementedException ${jsType}. ${jsinteropDoc}
- NotImplementedException ${elementType}
- NotImplementedException: bigint
- NotImplementedException: TypedArray
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/42ed0d3e1059cafd.
Report an issue: GitHub.