{"record":{"id":"ff68445ccc0f8d26","repo":"dotnet/runtime","slug":"argument-to-stringtointernedmonostringroot-must-be","errorCode":null,"errorMessage":"Argument to stringToInternedMonoStringRoot must be a string but was ${string}","messagePattern":"Argument to stringToInternedMonoStringRoot must be a string but was (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mono/browser/runtime/strings.ts","lineNumber":210,"sourceCode":"    }\n}\n\nfunction stringToInternedMonoStringRoot (string: string | symbol, result: WasmRoot<MonoString>): void {\n    let text: string | undefined;\n    if (typeof (string) === \"symbol\") {\n        text = string.description;\n        if (typeof (text) !== \"string\")\n            text = Symbol.keyFor(string);\n        if (typeof (text) !== \"string\")\n            text = \"<unknown Symbol>\";\n    } else if (typeof (string) === \"string\") {\n        text = string;\n    }\n\n    if (typeof (text) !== \"string\") {\n        // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n        // @ts-ignore\n        throw new Error(`Argument to stringToInternedMonoStringRoot must be a string but was ${string}`);\n    }\n\n    if ((text.length === 0) && _empty_string_ptr) {\n        result.set(_empty_string_ptr);\n        return;\n    }\n\n    const ptr = interned_js_string_table.get(text);\n    if (ptr) {\n        result.set(ptr);\n        return;\n    }\n\n    stringToMonoStringNewRoot(text, result);\n    storeStringInInternTable(text, result, true);\n}\n\nfunction storeStringInInternTable (string: string, root: WasmRoot<MonoString>, internIt: boolean): void {","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/mono/browser/runtime/strings.ts#L192-L228","documentation":"Thrown by stringToInternedMonoStringRoot when, after routing through the symbol/string branches, the resulting text variable is still not a string. In practice the symbol branch falls back to '<unknown Symbol>' so this is a defensive guard; it fires only if the input is neither a string nor a valid symbol and the routing logic did not assign text.","triggerScenarios":"Calling stringToInternedMonoStringRoot with a value that is neither string nor symbol, in a code path where the upstream typeof checks did not already redirect. Reachable if the function is invoked directly (it is not exported but is called by stringToMonoStringRoot for symbols/empty strings) with an unexpected type.","commonSituations":"Internal misuse of the private interned-string helper; a future refactor that adds a new accepted type but forgets to assign text; extremely rare in normal usage because stringToMonoStringRoot pre-filters inputs.","solutions":["Do not call stringToInternedMonoStringRoot directly; rely on stringToMonoStringRoot which type-checks first.","Ensure symbols passed in have a usable description or are registered with Symbol.keyFor so text resolves to a string.","If extending accepted types in this helper, make sure every branch assigns a string to text."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Do not call stringToInternedMonoStringRoot directly; go through stringToMonoStringRoot,\n// which pre-filters non-string/non-symbol values.\nstringToMonoStringRoot(input, root);","typeGuard":"function isStringOrSymbol(v: unknown): v is string | symbol {\n  return typeof v === 'string' || typeof v === 'symbol';\n}","tryCatchPattern":null,"preventionTips":["Keep stringToInternedMonoStringRoot internal-only; never export or call it directly.","Ensure symbols passed to interned conversion are registered via Symbol.keyFor or have a description.","Add tests covering symbol-without-description inputs."],"tags":["strings","validation","internal-error","interop","typescript"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}