{"record":{"id":"96cd9d205bfd43c4","repo":"moeru-ai/airi","slug":"worklet-loading-failed-err","errorCode":null,"errorMessage":"Worklet loading failed: ${err}","messagePattern":"Worklet loading failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/audio/src/audio-context/index.ts","lineNumber":73,"sourceCode":"    catch (err) {\n      console.error('AudioContext state listener error:', err)\n    }\n  })\n}\n\nasync function loadWorklets() {\n  if (!context || workletLoaded)\n    return\n\n  try {\n    await context.audioWorklet.addModule(ProcessorWorkletURL)\n    await context.audioWorklet.addModule(LibsamplerateWorkletURL)\n\n    workletLoaded = true\n  }\n  catch (err) {\n    console.error('Failed to load AudioWorklets:', err)\n    throw new Error(`Worklet loading failed: ${err}`)\n  }\n}\n\nexport async function initializeAudioContext(requestedSampleRate: number = 48000): Promise<AudioContext> {\n  // Use high quality base sample rate\n  const baseSampleRate = Math.max(requestedSampleRate, 48000)\n\n  if (context && isReady && sampleRate === baseSampleRate && workletLoaded) {\n    return context\n  }\n\n  if (isInitializing) {\n    return new Promise((resolve, reject) => {\n      const checkReady = () => {\n        if (!isInitializing) {\n          if (context && isReady && workletLoaded) {\n            resolve(context)\n          }","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/audio/src/audio-context/index.ts#L55-L91","documentation":"Thrown by loadWorklets() inside initializeAudioContext (packages/audio) when context.audioWorklet.addModule() rejects for either the processor or the libsamplerate worklet module. The underlying error is interpolated into the message and workletLoaded stays false, so the context is unusable for AudioWorkletNode processing until a later initializeAudioContext call succeeds.","triggerScenarios":"Calling initializeAudioContext() when ProcessorWorkletURL or LibsamplerateWorkletURL returns 404, is blocked by page CSP (worker-src/script-src), is served with a non-JavaScript MIME type, or when the worklet module itself throws during evaluation (syntax error, bad import).","commonSituations":"Bundler/dev-server does not emit the worklet files into build output; wrong base path so the URL resolves off-origin; strict Content-Security-Policy in Electron; CORS failure loading worklets from a CDN; worklet file references an identifier that does not exist in worklet scope.","solutions":["Read the wrapped error after 'Worklet loading failed:' — it names the exact addModule failure — and open the worklet URL directly (curl or browser tab) to check it returns 200 with a JavaScript MIME type","If 404: make sure the worklet assets are copied to the build output and the URL is derived from import.meta.url / the correct public base","If CSP-blocked: allow the worklet origin in worker-src and script-src (e.g. worker-src 'self' blob:)","If the module throws on evaluation: import the worklet file in a plain script context to surface the syntax/import error","Retry initializeAudioContext() after fixing — workletLoaded remains false so the load is reattempted"],"exampleFix":"// before\nawait initializeAudioContext(48000) // Error: Worklet loading failed: ...\n\n// after\ntry {\n  await initializeAudioContext(48000)\n}\ncatch (err) {\n  console.error('audio init failed, retrying once assets settle:', err)\n  await new Promise(r => setTimeout(r, 500))\n  await initializeAudioContext(48000) // workletLoaded stayed false, so loading is retried\n}","handlingStrategy":"try-catch","validationCode":"// Verify the worklet asset URLs your build actually serves are reachable before init\nfor (const url of workletAssetUrls) {\n  const res = await fetch(url)\n  if (!res.ok || !(res.headers.get('content-type') ?? '').includes('javascript'))\n    console.warn(`worklet asset problem: ${url} -> ${res.status}`)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await initializeAudioContext(48000)\n}\ncatch (err) {\n  // workletLoaded stays false, so a retry after fixing assets is safe\n  if (err instanceof Error && err.message.startsWith('Worklet loading failed')) {\n    reportAudioInitFailure(err) // inspect the wrapped cause, then retry or degrade gracefully\n  }\n  throw err\n}","preventionTips":["Ensure worklet files are emitted/copied in both dev and prod builds and URLs derive from import.meta.url","Add worker-src/script-src entries to CSP before shipping Electron/web apps","Treat initializeAudioContext as the single gate: never create AudioWorkletNodes outside code that ran after it resolved"],"tags":["web-audio","audio-worklet","initialization","csp"],"backgroundTag":"audioworklet-addmodule-failed","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}