{"record":{"id":"7e967d1076eca91d","repo":"moeru-ai/airi","slug":"whisperadapter-restarting-in-delay-ms-attempt","errorCode":null,"errorMessage":"[WhisperAdapter] Restarting in ${delay}ms (attempt ${restartAttempts}/${MAX_RESTARTS})","messagePattern":"\\[WhisperAdapter\\] Restarting in (.+?)ms \\(attempt (.+?)/(.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui/src/libs/inference/adapters/whisper.ts","lineNumber":185,"sourceCode":"      messageListener = null\n      errorListener = null\n      worker.terminate()\n      worker = null\n    }\n  }\n\n  function scheduleRestart(): void {\n    if (restartAttempts >= MAX_RESTARTS) {\n      console.error(`[WhisperAdapter] Max restart attempts (${MAX_RESTARTS}) reached.`)\n      // NOTICE: Transition to 'terminated' so callers can detect the dead adapter\n      // instead of being stuck in 'error' state indefinitely.\n      state = 'terminated'\n      return\n    }\n\n    restartAttempts++\n    const delay = RESTART_DELAY_MS * restartAttempts\n    console.warn(`[WhisperAdapter] Restarting in ${delay}ms (attempt ${restartAttempts}/${MAX_RESTARTS})`)\n\n    setTimeout(() => {\n      ensureWorker()\n    }, delay)\n  }\n\n  function onSuccess(): void {\n    restartAttempts = 0\n  }\n\n  function ensureWorker(): Worker {\n    if (!worker) {\n      worker = new Worker(workerUrl, { type: 'module' })\n      messageListener = (event: MessageEvent) => {\n        const data = event.data\n        // Forward unified protocol messages to subscribers\n        if (data.type === 'progress') {\n          const evt: WhisperEvent = { type: 'progress', payload: data.payload }","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui/src/libs/inference/adapters/whisper.ts#L167-L203","documentation":"WhisperAdapter supervises its transcription worker with the same bounded-restart policy as Kokoro: on worker failure scheduleRestart() waits RESTART_DELAY_MS × attempt and calls ensureWorker() again, warning per attempt. At MAX_RESTARTS it logs an error and sets state 'terminated' so callers can detect the dead adapter rather than waiting in 'error' forever. A successful restart clears the counter (onSuccess).","triggerScenarios":"Worker crash while loading or running the Whisper model (WASM abort, OOM), onnxruntime-web failures under webgpu execution provider, or the worker script failing to instantiate (404/bundle error).","commonSituations":"Memory-constrained tabs running ASR + TTS together; bundler misconfig serving a broken worker chunk; version skew between transformers.js and the whisper ONNX artifacts.","solutions":["Capture the worker's own error in devtools before this warn to find the root cause.","Reduce concurrent model loads (the GPU coordinator / load queue exists for this) to avoid OOM.","Fix worker bundling if ensureWorker fails instantly (check the worker URL loads standalone).","After 'terminated', obtain a fresh adapter (the getKokoroAdapter-style singleton reset) instead of retrying the dead one."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reset restartAttempts on success (onSuccess) so transient crashes do not accumulate toward termination.","Check state === 'terminated' before invoking the adapter and recreate it when needed.","Fix worker bundling issues before shipping: a 404 worker script produces instant restart loops."],"tags":["whisper","asr","web-worker","restart","backoff","inference"],"backgroundTag":"web-worker-crash","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}