dotnet/aspnetcore · error

Cannot create a JSObjectReference from the value '${jsObject

Error message

Cannot create a JSObjectReference from the value '${jsObject}'.

What it means

Thrown by createJSObjectReference() in Microsoft.JSInterop.ts (line 180) when the supplied value is not null/undefined and is not an object or function. JS object references are how JS hands a live object to .NET for later invocation; only real objects/functions can be tracked by id. Primitives (strings, numbers, booleans, symbols) and BigInts cannot be wrapped, so the function throws.

Source

Thrown at src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts:180

      if (jsObject === null || jsObject === undefined) {
          return {
              [jsObjectIdKey]: -1
          };
      }

      if (jsObject && (typeof jsObject === "object" || jsObject instanceof Function)) {
          cachedJSObjectsById[nextJsObjectId] = new JSObject(jsObject);

          const result = {
              [jsObjectIdKey]: nextJsObjectId
          };

          nextJsObjectId++;

          return result;
      }

      throw new Error(`Cannot create a JSObjectReference from the value '${jsObject}'.`);
  }

  /**
   * Creates a JavaScript data reference that can be passed to .NET via interop calls.
   *
   * @param streamReference The ArrayBufferView or Blob used to create the JavaScript stream reference.
   * @returns The JavaScript data reference (this will be the same instance as the given object).
   * @throws Error if the given value is not an Object or doesn't have a valid byteLength.
   */
  export function createJSStreamReference(streamReference: ArrayBuffer | ArrayBufferView | Blob | any): any {
      let length = -1;

      // If we're given a raw Array Buffer, we interpret it as a `Uint8Array` as
      // ArrayBuffers' aren't directly readable.
      if (streamReference instanceof ArrayBuffer) {
          streamReference = new Uint8Array(streamReference);
      }

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Pass only real objects or functions to createJSObjectReference; for primitives, return them directly and let JSON serialization handle them.
  2. If .NET expects IJSObjectReference, wrap the primitive in an object: { value: somePrimitive }.
  3. Align the JS return type with the .NET parameter type — change the .NET signature to a primitive if you only need the value.
  4. Add a typeof check before calling createJSObjectReference to fail with a clearer message.

Example fix

// before
const ref = DotNet.createJSObjectReference('hello'); // throws

// after
const ref = DotNet.createJSObjectReference({ value: 'hello' });
// or simply return the primitive and let interop JSON-serialize it
Defensive patterns

Strategy: type-guard

Validate before calling

function isWrappableObject(v: unknown): boolean {
  return v === null || v === undefined || (typeof v === 'object') || typeof v === 'function';
}

Type guard

function isJSObjectReferenceable(v: unknown): v is object | Function | null | undefined {
  return v === null || v === undefined || typeof v === 'object' || typeof v === 'function';
}

Prevention

When it happens

Trigger: Calling DotNet.createJSObjectReference(value) (or returning a primitive from a JSInvokable method that the runtime tries to wrap) where value is a string/number/boolean/symbol/bigint. Passing a primitive where .NET expects an IJSObjectReference.

Common situations: Returning a raw string/number from a JS interop function whose .NET signature expects IJSObjectReference. Wrapping a primitive 'by mistake' (e.g., createJSObjectReference(someString)). Trying to pass a DOM string property as an object reference. Migration from JSON-serialized interop to object-reference interop without changing what the JS returns.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/dad4d19e25ef68a0. Report an issue: GitHub.