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

  1. Change the C# array element type to a supported primitive: byte, int (Int32), double, float (Single), string, JSObject, or object.
  2. For 16-bit data, widen to int[] on the C# side and convert in JS with Int32Array.from(yourInt16Array) before the call.
  3. 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.
  4. 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

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


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/b175c6380a4a3542. Report an issue: GitHub.