dotnet/runtime · error · Error
address must be a location in the native heap
Error message
address must be a location in the native heap
What it means
Thrown by mono_wasm_new_external_root when the supplied address is falsy (0, null, undefined, or NaN-coerced-to-0). An external root must point at an existing location in the native heap; a null address has no slot for the runtime to register, so creation is rejected.
Source
Thrown at src/mono/browser/runtime/roots.ts:52
const offset = malloc(capacityBytes);
if ((<any>offset % 4) !== 0)
throw new Error("Malloc returned an unaligned offset");
_zero_region(offset, capacityBytes);
return new WasmRootBufferImpl(offset, capacity, true, name);
}
/**
* Allocates a WasmRoot pointing to a root provided and controlled by external code. Typicaly on managed stack.
* Releasing this root will not de-allocate the root space. You still need to call .release().
*/
export function mono_wasm_new_external_root<T extends MonoObject> (address: VoidPtr | MonoObjectRef): WasmRoot<T> {
if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported in multithreaded mode");
let result: WasmExternalRoot<T>;
if (!address)
throw new Error("address must be a location in the native heap");
if (_external_root_free_instances.length > 0) {
result = _external_root_free_instances.pop()!;
result._set_address(address);
} else {
result = new WasmExternalRoot<T>(address);
}
return result;
}
/**
* Allocates temporary storage for a pointer into the managed heap.
* Pointers stored here will be visible to the GC, ensuring that the object they point to aren't moved or collected.
* If you already have a managed pointer you can pass it as an argument to initialize the temporary storage.
* 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.
*/View on GitHub (pinned to 60108ba66e)
Solutions
- Ensure the address argument is a real native-heap location (e.g. from malloc or a stack alloc) before calling the API.
- Guard: skip external-root creation when the address is 0/null/undefined.
- Debug-print the address source upstream to find where the zero value originates.
Example fix
// before
const root = mono_wasm_new_external_root(maybeNullPtr);
// after
if (!maybeNullPtr) throw new Error('cannot create external root: slot not allocated');
const root = mono_wasm_new_external_root(maybeNullPtr); Defensive patterns
Strategy: type-guard
Validate before calling
function newExternalRootSafe(addr: VoidPtr | MonoObjectRef | null) {
if (!addr) throw new Error('slot not allocated');
return mono_wasm_new_external_root(addr);
} Type guard
function isNonNullAddress(a: unknown): a is number {
return typeof a === 'number' && a > 0;
} Prevention
- Always allocate the native slot before wrapping it as an external root.
- Treat a zero address from malloc/stack-alloc as a hard failure before reaching the root API.
- Initialize pointer fields to a sentinel and assert non-zero at the call site.
When it happens
Trigger: Calling mono_wasm_new_external_root(0), mono_wasm_new_external_root(null), mono_wasm_new_external_root(undefined), or passing a pointer variable that was never assigned a real native-heap address.
Common situations: Using an uninitialized pointer field as the root address; passing a MonoObjectRef that was zeroed; logic that conditionally allocates a native slot but always calls the root API; off-by-one that yields address 0.
Related errors
- capacity >= 1
- value must be an address in the managed heap
- count_or_values must be either an array or a number greater
- index out of range
- Expected runtimeOptions to be an array of strings
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/3aef11c901306776.
Report an issue: GitHub.