{"record":{"id":"752af34e320e5854","repo":"dotnet/runtime","slug":"implicit-conversion-of-roots-to-pointers-is-no-lon","errorCode":null,"errorMessage":"Implicit conversion of roots to pointers is no longer supported. Use .value or .address as appropriate","messagePattern":"Implicit conversion of roots to pointers is no longer supported\\. Use \\.value or \\.address as appropriate","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mono/browser/runtime/roots.ts","lineNumber":315,"sourceCode":"        const destinationAddress = this.address;\n        cwraps.mono_wasm_copy_managed_pointer(destinationAddress, source);\n    }\n\n    copy_to_address (destination: MonoObjectRef): void {\n        const sourceAddress = this.address;\n        cwraps.mono_wasm_copy_managed_pointer(destination, sourceAddress);\n    }\n\n    get value (): T {\n        return this.get();\n    }\n\n    set value (value: T) {\n        this.set(value);\n    }\n\n    valueOf (): T {\n        throw new Error(\"Implicit conversion of roots to pointers is no longer supported. Use .value or .address as appropriate\");\n    }\n\n    clear (): void {\n        // .set performs an expensive write barrier, and that is not necessary in most cases\n        //  for clear since clearing a root cannot cause new objects to survive a GC\n        const address32 = this.__buffer.get_address_32(this.__index);\n        localHeapViewU32()[address32] = 0;\n    }\n\n    release (): void {\n        if (!this.__buffer)\n            throw new Error(\"No buffer\");\n\n        const maxPooledInstances = 128;\n        if (_scratch_root_free_instances.length > maxPooledInstances) {\n            _mono_wasm_release_scratch_index(this.__index);\n            (<any>this).__buffer = null;\n            this.__index = 0;","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/mono/browser/runtime/roots.ts#L297-L333","documentation":"Thrown by WasmJsOwnedRoot.valueOf() to prevent implicit coercion of a scratch root into a primitive. Older code relied on valueOf to treat a root as a raw pointer; this was removed because it silently hid the distinction between a managed pointer (.value) and the address slot (.address). Any operation that triggers JS valueOf (arithmetic, string template, ==) on a scratch root now fails loudly.","triggerScenarios":"Writing root + 1, `${root}`, root == 0, or any expression that forces JS to call valueOf() on a WasmJsOwnedRoot instance. Also triggered by passing the root where a number is expected by an untyped API.","commonSituations":"Legacy interop code from before the valueOf removal; migrating code that treated roots as pointers; debugging statements like console.log(`ptr=${root}`); using == against 0 to test for null pointers.","solutions":["Replace implicit usage with root.value when you need the managed pointer, or root.address when you need the slot address.","For null-pointer checks use (root.value === 0) or root.get() === 0 instead of root == 0.","In template strings, interpolate root.value explicitly: `${root.value}`.","Run a grep for arithmetic and template usage of root variables to catch every site."],"exampleFix":"// before\nif (root == 0) { ... }\nconst s = `ptr ${root}`;\n// after\nif (root.value === 0) { ... }\nconst s = `ptr ${root.value}`;","handlingStrategy":"validation","validationCode":"// Lint-time guard: never use a root where a number/string is expected.\nconst v: number = root.value;       // managed pointer\nconst a: MonoObjectRef = root.address; // slot address","typeGuard":"function isWasmRoot<T>(r: unknown): r is WasmRoot<T> {\n  return !!r && typeof r === 'object' && 'value' in r && 'address' in r;\n}","tryCatchPattern":null,"preventionTips":["Add an ESLint rule (no-restricted-syntax) forbidding root identifiers in BinaryExpression/TemplateLiteral.","Code-review logging statements that interpolate roots.","Replace == 0 null checks with explicit .value === 0."],"tags":["gc-roots","api-change","valueof","typescript","migration"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}