{"record":{"id":"efce38405ddf6e2f","repo":"facefusion/facefusion","slug":"restoring-audio-skipped","errorCode":null,"errorMessage":"restoring_audio_skipped","messagePattern":"restoring_audio_skipped","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"facefusion/workflows/to_video.py","lineNumber":207,"sourceCode":"\t\tif source_audio_path:\n\t\t\tif ffmpeg.replace_audio(state_manager.get_item('target_path'), source_audio_path, state_manager.get_item('output_path')):\n\t\t\t\tvideo_manager.clear_video_pool()\n\t\t\t\tlogger.debug(translator.get('replacing_audio_succeeded'), __name__)\n\t\t\telse:\n\t\t\t\tvideo_manager.clear_video_pool()\n\t\t\t\tif is_process_stopping():\n\t\t\t\t\treturn 4\n\t\t\t\tlogger.warn(translator.get('replacing_audio_skipped'), __name__)\n\t\t\t\tmove_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))\n\t\telse:\n\t\t\tif ffmpeg.restore_audio(state_manager.get_item('target_path'), state_manager.get_item('output_path'), trim_frame_start, trim_frame_end):\n\t\t\t\tvideo_manager.clear_video_pool()\n\t\t\t\tlogger.debug(translator.get('restoring_audio_succeeded'), __name__)\n\t\t\telse:\n\t\t\t\tvideo_manager.clear_video_pool()\n\t\t\t\tif is_process_stopping():\n\t\t\t\t\treturn 4\n\t\t\t\tlogger.warn(translator.get('restoring_audio_skipped'), __name__)\n\t\t\t\tmove_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))\n\treturn 0\n\n\ndef finalize_video(start_time : float) -> ErrorCode:\n\tif is_video(state_manager.get_item('output_path')):\n\t\tlogger.info(translator.get('processing_video_succeeded').format(seconds = calculate_end_time(start_time)), __name__)\n\telse:\n\t\tlogger.error(translator.get('processing_video_failed'), __name__)\n\t\treturn 1\n\treturn 0\n","sourceCodeStart":189,"sourceCodeEnd":219,"githubUrl":"https://github.com/facefusion/facefusion/blob/4b1dedb853e4838ca7f3cf70b572be241aee2497/facefusion/workflows/to_video.py#L189-L219","documentation":"This warning is logged by FaceFusion's video workflow when the standard audio-restoration branch fails: ffmpeg.restore_audio() (which copies audio from the target video into the temp processed video within trim_frame_start..trim_frame_end) returned False. As with the replace-audio branch it is non-fatal — the video pool is cleared and move_temp_file promotes the temp file to output_path — so the workflow completes but the output video is missing the original audio. It usually stems from FFmpeg being unable to extract/remux the audio for the requested frame range, an unsupported audio codec, or missing temp/output paths.","triggerScenarios":"Running a video job without the conditional-audio option where ffmpeg.restore_audio(target_path, output_path, trim_frame_start, trim_frame_end) returns False because: (1) trim_frame_start/trim_frame_end define a range with no matching audio, (2) the target's audio codec is unsupported by the installed FFmpeg, (3) the temp processed video was removed (video pool cleared) or output_path is unwritable, (4) the process is stopping (the adjacent is_process_stopping() check returns exit code 4 before the warn in that case), or (5) FFmpeg is absent/outdated.","commonSituations":"Using --trim-frame-start/--trim-frame-end values that clip outside the audio timeline; processing videos with exotic audio (e.g. AC-3, Opus in odd containers) on a slim FFmpeg build; CI containers without FFmpeg encoders; cancelled jobs; outputs ending up silent and users filing 'no audio in result' issues.","solutions":["Verify FFmpeg presence/version (ffmpeg -version) and that the target's audio codec is supported (ffprobe target.mp4).","Check that trim_frame_start/trim_frame_end are within the video's frame range and that the range contains audio.","Ensure output_path directory exists and is writable, with enough disk space for the remux.","Avoid interrupting the job during finalization so the is_process_stopping() branch isn't taken.","If audio is still dropped, mux it back manually: ffmpeg -i out.mp4 -itsoffset <offset> -i target.mp4 -map 0:v -map 1:a -c copy final.mp4."],"exampleFix":"# before\npython facefusion.py run -s src.png -t clip.mp4 -o out.mp4 --trim-frame-start 0 --trim-frame-end 99999\n\n# after (valid range within video; verified audio codec)\nffprobe -v error -show_entries stream=nb_frames,codec_name clip.mp4\npython facefusion.py run -s src.png -t clip.mp4 -o out.mp4 --trim-frame-start 0 --trim-frame-end 250","handlingStrategy":"fallback","validationCode":"import subprocess, json, shutil\n\ndef audio_restorable(path: str, frame_start: int, frame_end: int) -> bool:\n    if not shutil.which('ffprobe'):\n        return False\n    probe = subprocess.run(['ffprobe', '-v', 'error', '-show_entries', 'stream=nb_frames,codec_type,codec_name', '-of', 'json', path], capture_output=True, text=True)\n    if probe.returncode != 0:\n        return False\n    streams = json.loads(probe.stdout).get('streams', [])\n    has_audio = any(s.get('codec_type') == 'audio' for s in streams)\n    nb_frames = max(int(s.get('nb_frames', 0) or 0) for s in streams if s.get('codec_type') == 'video') or None\n    in_range = nb_frames is None or (0 <= frame_start < nb_frames and frame_end >= frame_start)\n    return has_audio and in_range","typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["facefusion","ffmpeg","audio-restore","video-output","workflow-warning"],"backgroundTag":"ffmpeg-audio-mux-failed","analyzedSha":"4b1dedb853e4838ca7f3cf70b572be241aee2497","analyzedAt":"2026-08-28T15:25:13.662Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}