dotnet/runtime · error · Error

capacity >= 1

Error message

capacity >= 1

What it means

Thrown by mono_wasm_new_root_buffer when the supplied capacity is zero or negative. A root buffer must hold at least one GC root slot, so any non-positive capacity is rejected before any allocation occurs. It is a pure argument-validation guard at the top of the factory.

Source

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

import { gc_locked } from "./gc-lock";

const maxScratchRoots = 8192;
let _scratch_root_buffer: WasmRootBuffer | null = null;
let _scratch_root_free_indices: Int32Array | null = null;
let _scratch_root_free_indices_count = 0;
const _scratch_root_free_instances: WasmRoot<any>[] = [];
const _external_root_free_instances: WasmExternalRoot<any>[] = [];

/**
 * Allocates a block of memory that can safely contain pointers into the managed heap.
 * The result object has get(index) and set(index, value) methods that can be used to retrieve and store managed pointers.
 * Once you are done using the root buffer, you must call its release() method.
 * For small numbers of roots, it is preferable to use the mono_wasm_new_root and mono_wasm_new_roots APIs instead.
 */
export function mono_wasm_new_root_buffer (capacity: number, name?: string): WasmRootBuffer {
    if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported when threads are enabled");
    if (capacity <= 0)
        throw new Error("capacity >= 1");

    capacity = capacity | 0;

    const capacityBytes = capacity * 4;
    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> {

View on GitHub (pinned to 60108ba66e)

Solutions

  1. Guard the call: only allocate when the computed capacity is >= 1.
  2. If a zero-capacity case is legitimate for your caller, return early / use a no-op object instead of calling the API.
  3. Coerce with Math.max(1, capacity) only when at least one slot is genuinely required.

Example fix

// before
const buf = mono_wasm_new_root_buffer(items.length); // throws when items is empty
// after
if (items.length > 0) {
  const buf = mono_wasm_new_root_buffer(items.length);
}
Defensive patterns

Strategy: validation

Validate before calling

function safeRootBuffer(capacity: number) {
  if (!Number.isInteger(capacity) || capacity < 1) return null;
  return mono_wasm_new_root_buffer(capacity);
}

Type guard

function isValidCapacity(c: unknown): c is number {
  return typeof c === 'number' && Number.isInteger(c) && c >= 1;
}

Prevention

When it happens

Trigger: Calling mono_wasm_new_root_buffer(0), mono_wasm_new_root_buffer(-1), or passing a computed capacity that underflows to <= 0 (e.g. an array length of an empty input).

Common situations: Deriving capacity from a dynamic source such as args.length or an array size without clamping; off-by-one or off-by-zero when sizing a buffer from a count that is occasionally zero; passing an uninitialized/NaN number that coerces to 0.

Related errors


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