dotnet/runtime · error · Error

NotImplementedException

Error message

NotImplementedException ${elementType} 

What it means

Thrown by checkViewType (called from _marshalSpanToCs and _marshalArraySegmentToCs) when the elementType is anything other than Byte, Int32, Double, or Single. Spans and ArraySegments are restricted to those four memory-view element kinds because the marshaler must map the element type to a fixed MemoryViewType for direct heap access; any other element kind is unsupported.

Solutions

  1. Change the C# Span<T>/ArraySegment<T> element type to byte, int, double, or float.
  2. For char data, use byte spans and encode/decode UTF-8 on the JS side with dotnetBrowserUtilsExports.stringToUTF8 / utf8ToString.
  3. For 64-bit or other widths, marshal as an int[] or byte[] and widen on the C# side after the call.

Example fix

// before (C#)
[JSInvokable] public static void Fill(Span<char> buf) { /* ... */ } // throws NotImplementedException Char

// after (C#)
[JSInvokable] public static void Fill(Span<byte> utf8Buf) { /* decode UTF-8 on C# side */ }
Defensive patterns

Strategy: type-guard

Validate before calling

const SUPPORTED_VIEW_ELEM = new Set(['Byte','Int32','Double','Single']);

function isSupportedViewElement(elementType: string): boolean {
  return SUPPORTED_VIEW_ELEM.has(elementType);
}

if (!isSupportedViewElement(csharpElementType)) {
  throw new TypeError('Span/ArraySegment element type must be byte, int, double, or float');
}

Type guard

type SupportedViewElement = 'Byte' | 'Int32' | 'Double' | 'Single';
function isSupportedViewElement(t: string): t is SupportedViewElement {
  return ['Byte','Int32','Double','Single'].includes(t);
}

Try / catch

try {
  fillSpan(spanProxy);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('NotImplementedException ')) {
    throw new TypeError('Span/ArraySegment element type not supported; use byte/int/double/float', { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: A C# method accepts Span<T> or ArraySegment<T> with T other than byte/int/double/float (e.g. Span<char>, Span<long>, Span<nint>), and a JS caller invokes that interop boundary. Reached at marshal-to-cs.ts:517 when checkViewType cannot match the elementType to a MemoryViewType.

Common situations: Refactoring C# interop to use Span<char> for string-ish buffers, or Span<long>/Span<nint> assuming all primitive spans work. Trying to round-trip an ArraySegment<DateTimeOffset>. Updating to a runtime version that still has the four-type limit.

Related errors


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

Appendix: source

Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts:517

    dotnetAssert.check(gcHandle, "Only roundtrip of ArraySegment instance created by C#");
    checkViewType(elementType, value._viewType);
    setArgType(arg, MarshalerType.ArraySegment);
    setArgIntptr(arg, value._pointer);
    setArgLength(arg, value.length);
    setGcHandle(arg, gcHandle);
}

function checkViewType(elementType: MarshalerType, viewType: MemoryViewType) {
    if (elementType == MarshalerType.Byte) {
        dotnetAssert.check(MemoryViewType.Byte == viewType, "Expected MemoryViewType.Byte");
    } else if (elementType == MarshalerType.Int32) {
        dotnetAssert.check(MemoryViewType.Int32 == viewType, "Expected MemoryViewType.Int32");
    } else if (elementType == MarshalerType.Double) {
        dotnetAssert.check(MemoryViewType.Double == viewType, "Expected MemoryViewType.Double");
    } else if (elementType == MarshalerType.Single) {
        dotnetAssert.check(MemoryViewType.Single == viewType, "Expected MemoryViewType.Single");
    } else {
        throw new Error(`NotImplementedException ${elementType} `);
    }
}

View on GitHub (pinned to 60108ba66e)