dotnet/runtime · error · Error

Expected string argument, got ${typeof(string)}

Error message

Expected string argument, got ${typeof(string)}

What it means

Thrown by stringToMonoStringRoot when the input is not null, not a symbol, and not a string. The function converts a JS value to a Mono string root; only string, symbol, and null are accepted, and any other type (number, object, boolean, undefined) is rejected at line 173-174.

Source

Thrown at src/mono/browser/runtime/strings.ts:174

            result = mono_wasm_empty_string;
    }

    if (result === undefined)
        throw new Error(`internal error when decoding string at location ${root.value}`);

    return result;
}

export function stringToMonoStringRoot (string: string, result: WasmRoot<MonoString>): void {
    if (WasmEnableThreads) return;
    result.clear();

    if (string === null)
        return;
    else if (typeof (string) === "symbol")
        stringToInternedMonoStringRoot(string, result);
    else if (typeof (string) !== "string")
        throw new Error("Expected string argument, got " + typeof (string));
    else if (string.length === 0)
        // Always use an interned pointer for empty strings
        stringToInternedMonoStringRoot(string, result);
    else {
        // Looking up large strings in the intern table will require the JS runtime to
        //  potentially hash them and then do full byte-by-byte comparisons, which is
        //  very expensive. Because we can not guarantee it won't happen, try to minimize
        //  the cost of this and prevent performance issues for large strings
        if (string.length <= 256) {
            const interned = interned_js_string_table.get(string);
            if (interned) {
                result.set(interned);
                return;
            }
        }

        stringToMonoStringNewRoot(string, result);
    }

View on GitHub (pinned to 60108ba66e)

Solutions

  1. Coerce to string before calling: String(value) (or value == null ? null : String(value)).
  2. Type-narrow at the call site: branch on typeof value and only call stringToMonoStringRoot for 'string'/'symbol'/'object(null)'.
  3. Fix the upstream binding so it always supplies a string for string-typed parameters.

Example fix

// before
stringToMonoStringRoot(maybeNumber, root);
// after
stringToMonoStringRoot(maybeNumber == null ? null : String(maybeNumber), root);
Defensive patterns

Strategy: type-guard

Validate before calling

function toStringOrNullOrThrow(v: unknown): string | null {
  if (v === null) return null;
  if (typeof v === 'string' || typeof v === 'symbol') return v as string | symbol;
  throw new TypeError(`Expected string, got ${typeof v}`);
}

Type guard

function isStringLike(v: unknown): v is string | symbol | null {
  return v === null || typeof v === 'string' || typeof v === 'symbol';
}

Prevention

When it happens

Trigger: Calling stringToMonoStringRoot(123), stringToMonoStringRoot({}), stringToMonoStringRoot(true), or any non-string non-symbol non-null value. Null is allowed (early return), symbols are routed to the interned path.

Common situations: Interop code passing the wrong JS type into string conversion; an untyped binding that receives arbitrary values; a refactor where a value field changed from string to object without updating the call site.

Related errors


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