dotnet/runtime · error · Error
not implemented
Error message
not implemented
What it means
Thrown by marshalArrayToCsImpl at the final else branch when the array's elementType is not one of String/Object/JSObject/Byte/Int32/Double/Single. It signals that the C# side requested marshaling of a JS array (or typed array) whose declared element type is not on the supported list, so the marshaler refuses rather than corrupting the heap buffer.
Source
Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts:476
const targetView = dotnetApi.localHeapViewU8().subarray(bufferOffset, bufferOffset + length);
targetView.set(value);
} else if (elementType == MarshalerType.Int32) {
dotnetAssert.check(Array.isArray(value) || value instanceof Int32Array, "Value is not an Array or Int32Array");
const bufferOffset = fixupPointer(bufferPtr, 2);
const targetView = dotnetApi.localHeapViewI32().subarray(bufferOffset, bufferOffset + length);
targetView.set(value);
} else if (elementType == MarshalerType.Double) {
dotnetAssert.check(Array.isArray(value) || value instanceof Float64Array, "Value is not an Array or Float64Array");
const bufferOffset = fixupPointer(bufferPtr, 3);
const targetView = dotnetApi.localHeapViewF64().subarray(bufferOffset, bufferOffset + length);
targetView.set(value);
} else if (elementType == MarshalerType.Single) {
dotnetAssert.check(Array.isArray(value) || value instanceof Float32Array, "Value is not an Array or Float32Array");
const bufferOffset = fixupPointer(bufferPtr, 2);
const targetView = dotnetApi.localHeapViewF32().subarray(bufferOffset, bufferOffset + length);
targetView.set(value);
} else {
throw new Error("not implemented");
}
setArgIntptr(arg, bufferPtr);
setArgType(arg, MarshalerType.Array);
setArgElementType(arg, elementType);
setArgLength(arg, value.length);
}
}
function _marshalSpanToCs(arg: JSMarshalerArgument, value: Span, elementType?: MarshalerType): void {
dotnetAssert.check(!!elementType, "Expected valid elementType parameter");
dotnetAssert.check(!value.isDisposed, "ObjectDisposedException");
checkViewType(elementType, value._viewType);
setArgType(arg, MarshalerType.Span);
setArgIntptr(arg, value._pointer);
setArgLength(arg, value.length);
}
View on GitHub (pinned to 60108ba66e)
Solutions
- Change the C# array element type to a supported primitive: byte, int (Int32), double, float (Single), string, JSObject, or object.
- For 16-bit data, widen to int[] on the C# side and convert in JS with Int32Array.from(yourInt16Array) before the call.
- For numeric arrays not in the supported set, marshal as a typed array via Span<T>/ArraySegment<T> only for Byte/Int32/Double/Single element types.
- Rebuild both the C# assemblies and the dotnet wasm runtime so the marshaler type table and the C# signature agree.
Example fix
// before (C#) [JSInvokable] public static short[] Echo(short[] xs) => xs; // JS path throws "not implemented" // after (C#) [JSInvokable] public static int[] Echo(int[] xs) => xs; // Int32 element type supported
Defensive patterns
Strategy: type-guard
Validate before calling
const SUPPORTED_ARRAY_ELEM = new Set(['Byte','Int32','Double','Single','String','Object','JSObject']);
function isArrayElementTypeSupported(elementType: string): boolean {
return SUPPORTED_ARRAY_ELEM.has(elementType);
}
if (!isArrayElementTypeSupported(csharpElementType)) {
throw new TypeError(`Array element type ${csharpElementType} not supported by dotnet wasm marshaler`);
} Type guard
type SupportedArrayElement = 'Byte' | 'Int32' | 'Double' | 'Single' | 'String' | 'Object' | 'JSObject';
function isSupportedArrayElement(t: string): t is SupportedArrayElement {
return ['Byte','Int32','Double','Single','String','Object','JSObject'].includes(t);
} Try / catch
try {
invokeCSharpWithArray(values);
} catch (e) {
if (e instanceof Error && e.message === 'not implemented') {
throw new TypeError('C# array element type not supported; use byte/int/double/float/string/object/JSObject', { cause: e });
}
throw e;
} Prevention
- Restrict C# interop array signatures to byte[], int[], double[], float[], string[], object[], JSObject[].
- Convert Int16/UInt16/Char arrays to Int32Array before crossing the boundary.
- Rebuild both sides when changing an interop signature.
When it happens
Trigger: A C# interop signature declares an array of an unsupported element type (e.g. short[], char[], nint[], DateTime[], or a Nullable<T>[] / enum array) and a JS value is passed across that boundary. Also hit when marshalArrayToCsImpl is invoked directly with a MarshalerType that the array buffer-fill switch does not handle (Int16, Int52, BigInt64, Char, IntPtr, DateTimeOffset, etc.).
Common situations: Authoring a [JSInvokable]/[JSImport] method with an array of Int16/UInt16/Char/IntPtr and assuming all numeric arrays are supported. Migrating code from an array<int> to array<short>. Version drift where a newer C# signature added an element type the older wasm runtime never learned to marshal.
Related errors
- NotImplementedException ${elementType}. ${jsinteropDoc}
- NotImplementedException ${jsType}. ${jsinteropDoc}
- NotImplementedException ${elementType}
- NotImplementedException: bigint
- NotImplementedException: TypedArray
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/b175c6380a4a3542.
Report an issue: GitHub.