{"record":{"id":"734feab79e9b575d","repo":"heygen-com/hyperframes","slug":"audio-fx-input-is-missing-inputwav","errorCode":null,"errorMessage":"Audio FX input is missing: ${inputWav}","messagePattern":"Audio FX input is missing: (.+?)","errorType":"exception","errorClass":"AudioFxRenderError","httpStatus":null,"severity":"error","filePath":"packages/engine/src/services/audioFxRender.ts","lineNumber":202,"sourceCode":"\n/**\n * Run a chain over `inputWav`, writing `outputWav`. Resolves to the path to use\n * downstream: `outputWav` when the chain did something, `inputWav` untouched\n * when the chain was empty.\n *\n * Failure is fatal to the caller rather than a soft per-track warning: quietly\n * rendering the dry signal ships a mix that sounds plausible and is not what\n * the author set up.\n */\nexport async function applyAudioFxChain(\n  inputWav: string,\n  chain: HfAudioFxChain,\n  outputWav: string,\n  options: { trackId: string; signal?: AbortSignal },\n): Promise<string> {\n  if (enabledAudioFxNodes(chain).length === 0) return inputWav;\n  if (!existsSync(inputWav)) {\n    throw new AudioFxRenderError(`Audio FX input is missing: ${inputWav}`);\n  }\n\n  const { samples, sampleRate, channels } = readWav(inputWav);\n  const planes = deinterleave(samples, channels);\n\n  // Audio processing needs no GPU or special capture mode; a plain sandboxed\n  // browser is enough, and the lease pool reuses one across tracks.\n  const lease = await acquireBrowser([\n    \"--no-sandbox\",\n    \"--autoplay-policy=no-user-gesture-required\",\n  ]);\n  const hostDir = mkdtempSync(join(tmpdir(), \"hf-fx-host-\"));\n  try {\n    if (options.signal?.aborted) {\n      throw new AudioFxRenderError(`Audio FX cancelled for track ${options.trackId}`);\n    }\n    const page = await lease.browser.newPage();\n    try {","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/engine/src/services/audioFxRender.ts#L184-L220","documentation":"Thrown by applyAudioFxChain() when existsSync(inputWav) returns false — the WAV file that the FX chain is supposed to process does not exist on disk. The comment above the function explains this is a fatal error, not a soft warning, because silently rendering the dry signal produces a mix that sounds plausible but is not what the author configured.","triggerScenarios":"applyAudioFxChain(inputWav, chain, outputWav, options) is called after enabledAudioFxNodes(chain).length > 0 confirms there are active FX nodes, but the inputWav path does not resolve to an existing file. The check runs before readWav().","commonSituations":"The upstream capture/render step that should have produced the track WAV failed or was skipped. A temp-file path was garbage-collected or used a different tmpdir than expected. The trackId-to-path mapping in the producer pipeline has a bug. A render was interrupted between scheduling and execution.","solutions":["Check that the upstream render step for this track completed and wrote the WAV: verify with fs.existsSync(path) before calling applyAudioFxChain.","Inspect the path for typos, wrong tmpdir, or missing directory components.","If rendering in a serverless/container environment, ensure the temp volume is shared between the render and FX steps.","Log the trackId and resolved path in the producer's track scheduler to catch mapping bugs early."],"exampleFix":"// before\nawait applyAudioFxChain(inputWav, chain, outWav, opts);\n\n// after\nimport { existsSync } from 'fs';\nif (!existsSync(inputWav)) {\n  throw new Error(`Track ${opts.trackId}: upstream render did not produce ${inputWav}`);\n}\nawait applyAudioFxChain(inputWav, chain, outWav, opts);","handlingStrategy":"validation","validationCode":"import { existsSync, statSync } from 'fs';\n\nfunction validateInputWav(path: string): void {\n  if (!existsSync(path)) {\n    throw new Error(`Input WAV not found: ${path}. Check upstream render step.`);\n  }\n  const stat = statSync(path);\n  if (stat.size < 44) {\n    throw new Error(`Input WAV too small (${stat.size} bytes): ${path}`);\n  }\n}\n\nvalidateInputWav(inputWav);","typeGuard":null,"tryCatchPattern":"try {\n  await applyAudioFxChain(inputWav, chain, outWav, opts);\n} catch (err) {\n  if (err instanceof AudioFxRenderError && err.message.includes('input is missing')) {\n    // re-run upstream render, or mark track as failed\n  }\n  throw err;\n}","preventionTips":["Add a post-render assertion in the producer that each track WAV exists and is non-empty before scheduling FX.","Use deterministic temp paths derived from trackId to avoid path mapping bugs.","In serverless environments, use a shared volume or EFS for intermediate WAV files."],"tags":["audio","filesystem","pipeline","validation"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}