{"record":{"id":"7a16c92983caf2cd","repo":"moeru-ai/airi","slug":"bg-removal-worker-webgpu-not-available-falling","errorCode":null,"errorMessage":"[BG Removal Worker] WebGPU not available, falling back to WASM","messagePattern":"\\[BG Removal Worker\\] WebGPU not available, falling back to WASM","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui/src/workers/background-removal/worker.ts","lineNumber":145,"sourceCode":"        clearCancelled(requestId)\n        return\n      }\n      const ready: ModelReadyResponse = {\n        type: 'model-ready',\n        requestId,\n        modelId: MODEL_NAMES.BG_REMOVAL,\n        device: resolvedDevice,\n      }\n      globalThis.postMessage(ready)\n      return\n    }\n\n    // Auto-detect: if WebGPU was requested but unavailable, fall back to WASM\n    let device = request.device ?? 'webgpu'\n    if (device === 'webgpu') {\n      const hasWebGPU = await detectWebGPUInWorker()\n      if (!hasWebGPU) {\n        console.warn('[BG Removal Worker] WebGPU not available, falling back to WASM')\n        device = 'wasm'\n      }\n    }\n    resolvedDevice = device as 'webgpu' | 'wasm' | 'cpu'\n\n    env.backends.onnx.wasm!.proxy = false\n\n    model = await AutoModel.from_pretrained(MODEL_ID, {\n      device,\n      progress_callback: (progress: any) => {\n        sendProgress(requestId, progress?.progress ?? -1, progress?.status)\n      },\n    })\n\n    processor = await AutoProcessor.from_pretrained(MODEL_ID, {})\n\n    if (isCancelled(requestId)) {\n      clearCancelled(requestId)","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui/src/workers/background-removal/worker.ts#L127-L163","documentation":"The background-removal worker mirrors the Whisper worker's device probe: when a request asks for device 'webgpu' (the default when request.device is unset) but detectWebGPUInWorker() finds no navigator.gpu, it logs this, downgrades to device 'wasm', and sets env.backends.onnx.wasm.proxy = false so the ONNX model runs directly on the worker thread. Background removal still works, just on CPU/WASM at lower throughput.","triggerScenarios":"Any default request (or explicit device 'webgpu') in a browser/context without WebGPU: Firefox, older Chromium/Safari, driver blocklists, headless CI, VMs with software renderers, or worker scopes where navigator.gpu is not exposed.","commonSituations":"Users on WebGPU-less browsers experience slower background removal; automated screenshot pipelines; machines where the GPU driver is blocklisted.","solutions":["Verify WebGPU availability in that browser (chrome://gpu or 'gpu' in navigator)","Update the browser / drivers if the hardware supports WebGPU","Pass device: 'wasm' in the request to skip the probe and the warning when GPU absence is expected","Use a smaller bg-removal model or lower-resolution input to offset WASM latency"],"exampleFix":"// before\nworker.postMessage({ type: 'run', /* device defaults to 'webgpu' */ })\n\n// after\nconst device = 'gpu' in navigator ? 'webgpu' : 'wasm'\nworker.postMessage({ type: 'run', device })","handlingStrategy":"fallback","validationCode":"const device: 'webgpu' | 'wasm' = 'gpu' in navigator ? 'webgpu' : 'wasm'\nworker.postMessage({ type: 'run', requestId, device })","typeGuard":null,"tryCatchPattern":"try {\n  await runRemoval({ device: 'webgpu' })\n}\ncatch {\n  await runRemoval({ device: 'wasm' })\n}","preventionTips":["Pass an explicit device based on a main-thread navigator.gpu probe","Reduce input resolution for WASM-only environments","Remember env.backends.onnx.wasm.proxy is forced false in this worker - keep heavy work off the main thread"],"tags":["webgpu","wasm","background-removal","transformers-js","device-fallback"],"backgroundTag":"webgpu-not-available","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}