{"record":{"id":"741949077d946fd3","repo":"moeru-ai/airi","slug":"audiocontext-or-worklets-not-ready","errorCode":null,"errorMessage":"AudioContext or worklets not ready","messagePattern":"AudioContext or worklets not ready","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/audio/src/audio-context/index.ts","lineNumber":227,"sourceCode":"  if (context && context.state === 'running') {\n    await context.suspend()\n    notifyListeners()\n  }\n}\n\nexport async function resumeAudioContext() {\n  if (context && context.state === 'suspended') {\n    await context.resume()\n    notifyListeners()\n  }\n}\n\nexport function createResamplingWorkletNode(\n  inputNode: AudioNode,\n  options: WorkletOptions = {},\n): AudioWorkletNode {\n  if (!context || !isReady || !workletLoaded) {\n    throw new Error('AudioContext or worklets not ready')\n  }\n\n  const workletOptions = {\n    inputSampleRate: sampleRate,\n    outputSampleRate: 16000,\n    channels: 1,\n    converterType: 2, // SRC_SINC_MEDIUM_QUALITY\n    bufferSize: 4096,\n    ...options,\n  }\n\n  const workletNode = new AudioWorkletNode(context, 'resampling-processor', {\n    numberOfInputs: 1,\n    numberOfOutputs: 1,\n    channelCount: workletOptions.channels,\n    processorOptions: workletOptions,\n  })\n","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/audio/src/audio-context/index.ts#L209-L245","documentation":"createResamplingWorkletNode applies a stricter guard than the other factories: it requires context AND isReady AND workletLoaded. The resampling worklet node depends on the libsamplerate worklet module, so even if the AudioContext is ready, a failed/skipped loadWorklets leaves workletLoaded false and this function refuses to construct the node.","triggerScenarios":"initializeAudioContext succeeded the context but loadWorklets failed (error 190) so workletLoaded stayed false; calling before initializeAudioContext completes; the worklet loaded flag was reset after teardown.","commonSituations":"Audio init partially succeeded (context up, worklets failed) and the caller assumes full readiness; insecure context allows a context but not AudioWorklet; bundler emitted the context init but not the worklet files.","solutions":["Ensure loadWorklets() completed (no error 190) before constructing resampling nodes.","Subscribe to a readiness state that includes workletLoaded, not just isReady.","Degrade to a non-worklet resampling path when workletLoaded is false."],"exampleFix":"// before\nconst node = createResamplingWorkletNode(inputNode)\n\n// after\nawait initializeAudioContext()\nif (!workletLoaded) {\n  throw new Error('Resampling requires AudioWorklet support; ensure loadWorklets succeeded')\n}\nconst node = createResamplingWorkletNode(inputNode)","handlingStrategy":"validation","validationCode":"if (!context || !isReady || !workletLoaded) {\n  throw new Error('Resampling node requires AudioContext ready AND worklets loaded')\n}","typeGuard":"function isWorkletReady(): boolean {\n  return !!context && isReady && workletLoaded\n}","tryCatchPattern":"try {\n  return createResamplingWorkletNode(inputNode, options)\n}\ncatch (err) {\n  if (/worklets not ready/i.test((err as Error).message)) {\n    // fall back to a ScriptProcessorNode or non-resampling path\n    return createFallbackResampler(inputNode, options)\n  }\n  throw err\n}","preventionTips":["Ensure loadWorklets() completed before constructing resampling nodes.","Track a readiness flag that includes workletLoaded, not just isReady.","Provide a non-worklet fallback for environments where AudioWorklet is unavailable."],"tags":["web-audio","audioworklet","lifecycle","initialization","resampling"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}