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
- Coerce to string before calling: String(value) (or value == null ? null : String(value)).
- Type-narrow at the call site: branch on typeof value and only call stringToMonoStringRoot for 'string'/'symbol'/'object(null)'.
- 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
- Always coerce non-string values with String() at the interop boundary.
- Type interop string parameters as string strictly.
- Unit-test the binding with each primitive type to catch regressions.
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
- Argument to stringToInternedMonoStringRoot must be a string
- capacity >= 1
- value must be an address in the managed heap
- count_or_values must be either an array or a number greater
- Expected runtimeOptions to be an array of strings
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/6d632610a69b8595.
Report an issue: GitHub.