moeru-ai/airi · warning

[WhisperAdapter] ${deviceLossCount} device-loss events recor

Error message

[WhisperAdapter] ${deviceLossCount} device-loss events recorded, promoting load from webgpu to wasm.

What it means

WhisperAdapter.load() checks the shared device-loss counter; when deviceLossCount >= DEVICE_LOSS_WASM_THRESHOLD it requests 'wasm' instead of the usual 'webgpu' and warns about the promotion. Rationale mirrors kokoro.ts: after repeated WebGPU device-loss events on this device, webgpu is treated as persistently unreliable and the adapter proactively falls back to the slower-but-stable wasm backend.

Source

Thrown at packages/stage-ui/src/libs/inference/adapters/whisper.ts:310

          w.postMessage({ type: 'cancel', requestId: createRequestId(), targetRequestId: requestId })
          const reason = signal.reason
          reject(reason instanceof Error ? reason : new InferenceAbortError(typeof reason === 'string' ? reason : undefined))
        }
        signal.addEventListener('abort', abortListener)
      }
    })
  }

  async function load(
    onProgress?: (p: ProgressPayload) => void,
    options?: { signal?: AbortSignal },
  ): Promise<void> {
    // NOTICE: Proactive WASM promotion after repeated device-loss events.
    // See kokoro.ts for rationale. Whisper always requests 'webgpu' from the
    // caller today, so we only check the promotion threshold.
    const requestedDevice = deviceLossCount >= DEVICE_LOSS_WASM_THRESHOLD ? 'wasm' : 'webgpu'
    if (requestedDevice === 'wasm') {
      console.warn(
        `[WhisperAdapter] ${deviceLossCount} device-loss events recorded, `
        + `promoting load from webgpu to wasm.`,
      )
    }
    throwIfAborted(options?.signal)
    return operationMutex.runExclusive(async () => {
      throwIfAborted(options?.signal)
      state = 'loading'
      updateInferenceStatus(MODEL_NAMES.WHISPER, { state: 'downloading', device: requestedDevice as any })

      return getLoadQueue().enqueue(MODEL_NAMES.WHISPER, LOAD_PRIORITY.ASR, async () => {
        throwIfAborted(options?.signal)
        const w = ensureWorker()
        const requestId = createRequestId()

        const readyPromise = waitForMessage(w, requestId, 'model-ready', LOAD_TIMEOUT, (data) => {
          if (data.type === 'progress' && onProgress) {
            const payload = data.payload

View on GitHub (pinned to 677329427f)

Solutions

  1. Accept the wasm fallback for ASR (latency rises, correctness unchanged).
  2. Update browser/drivers to reduce device-loss frequency so the threshold is never reached.
  3. If reproducible on your hardware, file the device-loss pattern against the browser's WebGPU tracker.
  4. To avoid the warn in kiosks, pre-select wasm for whisper on known-bad devices.
Defensive patterns

Strategy: fallback

Validate before calling

const requested = adapterHasDeviceLosses(deviceLossCount) ? 'wasm' : 'webgpu'

Prevention

When it happens

Trigger: Whisper load following one or more WebGPU device-loss events earlier in the session (possibly from another model's run); drivers/browsers with flaky WebGPU compute for conv nets.

Common situations: Same-machine sessions where kokoro already lost the device; hybrid-GPU laptops; long-running sessions after a driver reset.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/b9a57b10500bb7bd. Report an issue: GitHub.