{"record":{"id":"b1d39d9e9b7f60e4","repo":"heygen-com/hyperframes","slug":"no-frames-produced-from-inputpath-decoder-stde","errorCode":null,"errorMessage":"No frames produced from ${inputPath}. Decoder stderr:\n${decoder.getStderr().slice(-400)}","messagePattern":"No frames produced from (.+?)\\. Decoder stderr:\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/background-removal/pipeline.ts","lineNumber":462,"sourceCode":"        total,\n        avgMsPerFrame: recentSum / recentCount,\n      });\n    }\n  } catch (err) {\n    decoder.proc.kill(\"SIGKILL\");\n    fg.proc.kill(\"SIGKILL\");\n    bg?.proc.kill(\"SIGKILL\");\n    throw err;\n  }\n\n  fg.proc.stdin!.end();\n  bg?.proc.stdin!.end();\n  const exits: Promise<void>[] = [decoder.exit, fg.exit];\n  if (bg) exits.push(bg.exit);\n  await Promise.all(exits);\n\n  if (processed === 0) {\n    throw new Error(\n      `No frames produced from ${inputPath}. Decoder stderr:\\n${decoder.getStderr().slice(-400)}`,\n    );\n  }\n\n  return processed;\n}\n\nexport function waitForExit(\n  proc: ReturnType<typeof spawn>,\n  label: string,\n  getStderr: () => string,\n): Promise<void> {\n  return new Promise<void>((resolve, reject) => {\n    proc.on(\"error\", reject);\n    // Per Node docs the exit callback is (code, signal): on a normal exit\n    // `code` is the numeric exit status and `signal` is null; on a\n    // signal-killed exit `code` is null and `signal` is the signal name.\n    // Treating null-code as success would silently report SIGTERM/SIGKILL","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/background-removal/pipeline.ts#L444-L480","documentation":"Thrown at the end of runPipeline() after the ffmpeg decoder process finishes and produces zero frames (processed === 0). The pipeline decodes the input via `ffmpeg -i <input> -f rawvideo -pix_fmt rgb24 -` and iterates the stdout stream; if nothing came through, the decoder's stderr tail is appended so the root cause (codec unsupported, corrupt input, wrong path) is visible rather than an opaque 'no output'.","triggerScenarios":"Calling render() with a path that ffmpeg cannot decode: a corrupted mp4, a file with an unsupported codec (e.g. HEVC on a minimal ffmpeg build), a zero-byte file, a wrong path that ffmpeg still opens but cannot read, or a container/codec mismatch.","commonSituations":"Truncated/corrupted download passed as input; a minimal ffmpeg build without libx265 decoding a HEVC clip; the file path is a directory or pipe instead of a regular file; mismatched extension vs actual container.","solutions":["Read the decoder stderr tail in the error message — it usually names the real cause (e.g. 'Unknown codec', 'Invalid data found', 'No such file').","Test the input independently: `ffmpeg -i <input> -f null -` and fix based on the reported error.","If the codec is unsupported, re-encode to H.264/AAC mp4: `ffmpeg -i in.mkv -c:v libx264 -c:a aac out.mp4`.","If the file is corrupt, re-download or re-export the source."],"exampleFix":"# before — input is HEVC but ffmpeg lacks libx265\n$ hyperframes bg-remove -i hevc_clip.mp4 ...\n# re-encode to a broadly supported codec\n$ ffmpeg -i hevc_clip.mp4 -c:v libx264 -preset fast -crf 18 h264_clip.mp4\n$ hyperframes bg-remove -i h264_clip.mp4 ...","handlingStrategy":"try-catch","validationCode":"import { execFileSync } from 'node:child_process';\nfunction inputDecodes(inputPath: string): boolean {\n  try {\n    execFileSync('ffmpeg', ['-i', inputPath, '-f', 'null', '-'], { stdio: 'ignore', timeout: 30_000 });\n    return true;\n  } catch {\n    return false;\n  }\n}\nif (!inputDecodes(options.inputPath)) {\n  throw new Error(`Input cannot be decoded by ffmpeg: ${options.inputPath}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await render(options);\n} catch (err) {\n  const msg = (err as Error).message;\n  if (/No frames produced/.test(msg)) {\n    console.error('Decoder produced no frames. Check the stderr tail:\\n' + msg);\n    // re-encode the input, then retry\n  }\n  throw err;\n}","preventionTips":["Pre-validate the input with `ffmpeg -i <input> -f null -` before the render.","For user-supplied uploads, reject files ffprobe cannot read.","Keep ffmpeg builds current so common codecs (H.264/H.265) are supported."],"tags":["ffmpeg","decode-failure","corrupt-input","background-removal","runtime"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}