moeru-ai/airi · error · Error

Invalid VRAM override: ${bytes} (expected null or non-negati

Error message

Invalid VRAM override: ${bytes} (expected null or non-negative finite number)

What it means

`setEstimatedVRAMOverride(bytes)` accepts either `null` (to clear the override and revert to the heuristic) or a non-negative finite number of bytes. It throws `Invalid VRAM override: <bytes> (expected null or non-negative finite number)` when `bytes` is not `null` and either `Number.isFinite(bytes)` is false or `bytes < 0`. This guards against `NaN`, `Infinity`, negatives, and non-numeric coercion.

Source

Thrown at packages/stage-shared/src/webgpu/detect.ts:226

 * Simple boolean helper that matches the old `isWebGPUSupported()` API.
 * Prefer `detectWebGPU()` when you need more detail.
 */
export async function isWebGPUSupported(): Promise<boolean> {
  // Fast-path: if gpuu's lightweight check is enough
  return gpuuIsSupported()
}

/**
 * Override the estimated VRAM value. Pass `null` to clear the override and
 * revert to the heuristic. The override applies to future detections, and if
 * a result is already cached its VRAM fields are updated immediately, so
 * `resetWebGPUCache()` is not required.
 *
 * Intended for user preference UI ("I have 8 GB VRAM") and testing.
 */
export function setEstimatedVRAMOverride(bytes: number | null): void {
  if (bytes !== null && (!Number.isFinite(bytes) || bytes < 0))
    throw new Error(`Invalid VRAM override: ${bytes} (expected null or non-negative finite number)`)

  vramOverride = bytes

  // If we already have a cached result, update it in-place so consumers
  // see the new value without needing to call resetWebGPUCache(). The
  // original heuristic value is preserved in `cachedHeuristicVRAM` so we
  // can revert when the override is cleared.
  if (cachedResult) {
    const vram = resolveVRAM(cachedHeuristicVRAM)
    cachedResult = {
      ...cachedResult,
      estimatedVRAM: vram.bytes,
      estimatedVRAMSource: vram.source,
    }
  }
}

/** Read the current VRAM override, or null if unset. */

View on GitHub (pinned to 27111382b4)

Solutions

  1. Coerce and validate before calling: parse digits, then `Number.isFinite(n) && n >= 0 ? n : null`.
  2. Use `null` (not `0` or `-1`) as the sentinel for 'no override / use heuristic'.
  3. If the UI gives gigabytes, convert: `Math.round(gb * 1024 ** 3)`.
  4. Handle empty input explicitly by passing `null` rather than forwarding `NaN`.

Example fix

// before
setEstimatedVRAMOverride(Number(inputEl.value))

// after
const raw = inputEl.value.trim()
const gb = raw === '' ? null : Number(raw)
const bytes = gb == null || !Number.isFinite(gb) ? null : Math.round(gb * 1024 ** 3)
setEstimatedVRAMOverride(bytes)
Defensive patterns

Strategy: validation

Validate before calling

function toVRAMBytes(gb: string | number | null | undefined): number | null {
  if (gb == null || gb === '') return null
  const n = typeof gb === 'number' ? gb : Number(gb)
  if (!Number.isFinite(n) || n < 0) return null
  return Math.round(n * 1024 ** 3)
}

setEstimatedVRAMOverride(toVRAMBytes(userInput))

Type guard

function isValidVRAMOverride(bytes: unknown): bytes is number | null {
  return bytes === null || (typeof bytes === 'number' && Number.isFinite(bytes) && bytes >= 0)
}

Try / catch

try {
  setEstimatedVRAMOverride(value as number | null)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid VRAM override')) {
    setEstimatedVRAMOverride(null)  // revert to heuristic
  } else throw e
}

Prevention

When it happens

Trigger: Calling `setEstimatedVRAMOverride(NaN)`, `setEstimatedVRAMOverride(Infinity)`, `setEstimatedVRAMOverride(-1)`, or passing a parsed value that came back as `NaN` from `Number('')` / `Number(undefined)` / `parseFloat('garbage')`. Passing `undefined` (coerced via template literal) also triggers it.

Common situations: A settings UI where the VRAM field was left empty and `Number(input)` produced `NaN`; parsing a string like `"8 GB"` directly with `Number()` instead of extracting digits; unit mismatch (passing gigabytes where bytes are expected is not an error but a logic bug); a slider returning `-1` for 'unset'.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/17c99eecb0c2f92d. Report an issue: GitHub.