{"record":{"id":"d8406121966eb501","repo":"heygen-com/hyperframes","slug":"audio-fx-failed-for-track-options-trackid-e","errorCode":null,"errorMessage":"Audio FX failed for track ${options.trackId}: ${(err as Error).message}","messagePattern":"Audio FX failed for track (.+?): (.+?)","errorType":"exception","errorClass":"AudioFxRenderError","httpStatus":null,"severity":"error","filePath":"packages/engine/src/services/audioFxRender.ts","lineNumber":283,"sourceCode":"\n      // byteOffset and byteLength matter: Node pools small allocations, so a\n      // short payload decodes into an 8 KiB pool and a view over the whole\n      // ArrayBuffer would read kilobytes of unrelated memory at the wrong length.\n      const outPlanes = rendered.map((b64) => {\n        const buf = Buffer.from(b64, \"base64\");\n        return new Float32Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));\n      });\n      if (outPlanes.length === 0 || (outPlanes[0]?.length ?? 0) === 0) {\n        throw new AudioFxRenderError(`Audio FX produced no samples for track ${options.trackId}`);\n      }\n      writeWav(outputWav, interleave(outPlanes), sampleRate, outPlanes.length);\n      return outputWav;\n    } finally {\n      await page.close().catch(() => undefined);\n    }\n  } catch (err) {\n    if (err instanceof AudioFxRenderError) throw err;\n    throw new AudioFxRenderError(\n      `Audio FX failed for track ${options.trackId}: ${(err as Error).message}`,\n    );\n  } finally {\n    rmSync(hostDir, { recursive: true, force: true });\n    await lease.release().catch(() => undefined);\n  }\n}\n\nexport type { HfAudioFxChain };\n","sourceCodeStart":265,"sourceCodeEnd":293,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/engine/src/services/audioFxRender.ts#L265-L293","documentation":"Catch-all wrapper thrown by the outer try/catch in applyAudioFxChain() for any error that is NOT already an AudioFxRenderError. The inner catch checks instanceof AudioFxRenderError and re-throws those as-is; everything else (browser crashes, page.evaluate exceptions, network errors, unexpected throws) gets wrapped with the trackId and original message for diagnostics. The finally clause still releases the browser lease and removes the temp directory.","triggerScenarios":"Any unhandled exception during page setup, script injection, page.evaluate, or WAV writing that isn't already an AudioFxRenderError. The original error's message is appended to give context. Common inner errors: 'Target closed' (browser crashed), 'Evaluation failed' (JS error in page), 'Navigation timeout'.","commonSituations":"Headless Chrome crashed (OOM, segfault) during FX processing. The page navigated or closed unexpectedly. A JS error inside the evaluate callback (not the __HF_AUDIO_FX check, which is caught separately) propagated. Puppeteer protocol error due to browser disconnect.","solutions":["Read the appended original message: 'Audio FX failed for track X: <original>' — the original message is the real diagnostic.","If 'Target closed' / 'Browser disconnected': check Chrome memory limits, add --disable-dev-shm-usage or increase container memory.","If 'Evaluation failed': debug the runtime script in a standalone browser.","Add retry logic around applyAudioFxChain for transient browser crashes, with a fresh browser lease per attempt."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await applyAudioFxChain(inputWav, chain, outWav, opts);\n} catch (err) {\n  if (err instanceof AudioFxRenderError && err.message.includes('Audio FX failed for track')) {\n    // extract inner message, check for browser crash / target closed\n    const inner = err.message.split(': ').slice(1).join(': ');\n    if (inner.includes('Target closed') || inner.includes('disconnected')) {\n      // retry with a fresh browser lease\n    }\n  }\n  throw err;\n}","preventionTips":["Monitor Chrome process memory; add --disable-dev-shm-usage in memory-constrained containers.","Implement retry with a fresh browser lease for transient crashes.","Log the full inner error message for post-mortem diagnostics."],"tags":["audio","browser","error-wrapping","diagnostics","puppeteer"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}