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
- Coerce and validate before calling: parse digits, then `Number.isFinite(n) && n >= 0 ? n : null`.
- Use `null` (not `0` or `-1`) as the sentinel for 'no override / use heuristic'.
- If the UI gives gigabytes, convert: `Math.round(gb * 1024 ** 3)`.
- 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
- Use null (not 0 or -1) as the 'no override' sentinel.
- Coerce and validate user GB input to finite bytes before calling.
- Guard sliders/text fields with Number.isFinite and >= 0.
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
- Artistry provider is disabled.
- Provider '${requestedProvider}' not found.
- Nano Banana API Key not configured
- ${issue.path.join('.') || '<root>'}: ${issue.message}
- invalid JSON: ${stringifyError(error)}
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/17c99eecb0c2f92d.
Report an issue: GitHub.