{"record":{"id":"17c99eecb0c2f92d","repo":"moeru-ai/airi","slug":"invalid-vram-override-bytes-expected-null-or","errorCode":null,"errorMessage":"Invalid VRAM override: ${bytes} (expected null or non-negative finite number)","messagePattern":"Invalid VRAM override: (.+?) \\(expected null or non-negative finite number\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-shared/src/webgpu/detect.ts","lineNumber":226,"sourceCode":" * Simple boolean helper that matches the old `isWebGPUSupported()` API.\n * Prefer `detectWebGPU()` when you need more detail.\n */\nexport async function isWebGPUSupported(): Promise<boolean> {\n  // Fast-path: if gpuu's lightweight check is enough\n  return gpuuIsSupported()\n}\n\n/**\n * Override the estimated VRAM value. Pass `null` to clear the override and\n * revert to the heuristic. The override applies to future detections, and if\n * a result is already cached its VRAM fields are updated immediately, so\n * `resetWebGPUCache()` is not required.\n *\n * Intended for user preference UI (\"I have 8 GB VRAM\") and testing.\n */\nexport function setEstimatedVRAMOverride(bytes: number | null): void {\n  if (bytes !== null && (!Number.isFinite(bytes) || bytes < 0))\n    throw new Error(`Invalid VRAM override: ${bytes} (expected null or non-negative finite number)`)\n\n  vramOverride = bytes\n\n  // If we already have a cached result, update it in-place so consumers\n  // see the new value without needing to call resetWebGPUCache(). The\n  // original heuristic value is preserved in `cachedHeuristicVRAM` so we\n  // can revert when the override is cleared.\n  if (cachedResult) {\n    const vram = resolveVRAM(cachedHeuristicVRAM)\n    cachedResult = {\n      ...cachedResult,\n      estimatedVRAM: vram.bytes,\n      estimatedVRAMSource: vram.source,\n    }\n  }\n}\n\n/** Read the current VRAM override, or null if unset. */","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-shared/src/webgpu/detect.ts#L208-L244","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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'.","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`."],"exampleFix":"// before\nsetEstimatedVRAMOverride(Number(inputEl.value))\n\n// after\nconst raw = inputEl.value.trim()\nconst gb = raw === '' ? null : Number(raw)\nconst bytes = gb == null || !Number.isFinite(gb) ? null : Math.round(gb * 1024 ** 3)\nsetEstimatedVRAMOverride(bytes)","handlingStrategy":"validation","validationCode":"function toVRAMBytes(gb: string | number | null | undefined): number | null {\n  if (gb == null || gb === '') return null\n  const n = typeof gb === 'number' ? gb : Number(gb)\n  if (!Number.isFinite(n) || n < 0) return null\n  return Math.round(n * 1024 ** 3)\n}\n\nsetEstimatedVRAMOverride(toVRAMBytes(userInput))","typeGuard":"function isValidVRAMOverride(bytes: unknown): bytes is number | null {\n  return bytes === null || (typeof bytes === 'number' && Number.isFinite(bytes) && bytes >= 0)\n}","tryCatchPattern":"try {\n  setEstimatedVRAMOverride(value as number | null)\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Invalid VRAM override')) {\n    setEstimatedVRAMOverride(null)  // revert to heuristic\n  } else throw e\n}","preventionTips":["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."],"tags":["input-validation","webgpu","vram","config"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}