dotnet/runtime · error · Error

value must be an address in the managed heap

Error message

value must be an address in the managed heap

What it means

Thrown by mono_wasm_new_root when an initial value is supplied that is not undefined and not a number. Managed-heap addresses are represented as numeric pointers; passing an object, string, or other type as the initial value cannot be stored as a managed pointer, so it is rejected.

Source

Thrown at src/mono/browser/runtime/roots.ts:86

 * The result object has get() and set(value) methods, along with a .value property.
 * When you are done using the root you must call its .release() method.
 */
export function mono_wasm_new_root<T extends MonoObject> (value: T | undefined = undefined): WasmRoot<T> {
    if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported in multithreaded mode");
    let result: WasmRoot<T>;

    if (_scratch_root_free_instances.length > 0) {
        result = _scratch_root_free_instances.pop()!;
    } else {
        const index = _mono_wasm_claim_scratch_index();
        const buffer = _scratch_root_buffer;

        result = new WasmJsOwnedRoot(buffer!, index);
    }

    if (value !== undefined) {
        if (typeof (value) !== "number")
            throw new Error("value must be an address in the managed heap");

        result.set(value);
    } else {
        result.set(<any>0);
    }

    return result;
}

/**
 * Allocates 1 or more temporary roots, accepting either a number of roots or an array of pointers.
 * mono_wasm_new_roots(n): returns an array of N zero-initialized roots.
 * mono_wasm_new_roots([a, b, ...]) returns an array of new roots initialized with each element.
 * Each root must be released with its release method, or using the mono_wasm_release_roots API.
 */
export function mono_wasm_new_roots<T extends MonoObject> (count_or_values: number | T[]): WasmRoot<T>[] {
    let result;

View on GitHub (pinned to 60108ba66e)

Solutions

  1. Pass a numeric managed-heap address, or pass undefined for zero-initialization.
  2. If you have a WasmRoot, use root.value or root.address to get the numeric pointer first.
  3. Add a typeof check at the call site to fail with a clearer upstream message.

Example fix

// before
const r = mono_wasm_new_root(otherRoot); // otherRoot is an object
// after
const r = mono_wasm_new_root(otherRoot.value); // numeric pointer
Defensive patterns

Strategy: type-guard

Validate before calling

function newRootSafe(value?: number) {
  if (value !== undefined && typeof value !== 'number') {
    throw new TypeError('initial value must be a numeric managed pointer or undefined');
  }
  return mono_wasm_new_root(value);
}

Type guard

function isManagedPointer(v: unknown): v is number {
  return v === undefined || (typeof v === 'number' && Number.isFinite(v));
}

Prevention

When it happens

Trigger: Calling mono_wasm_new_root(someObject), mono_wasm_new_root('a string'), or any call where the second argument is defined but typeof value !== 'number'. Passing undefined is allowed (zero-initializes the root).

Common situations: Accidentally passing a JS wrapper or WasmRoot instance instead of its .value/.address; a refactor that changed the parameter type without updating call sites; passing a managed object handle object rather than its numeric id.

Related errors


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