ATH-MaaS/Pixelle-Video · error · RuntimeError
Failed to concatenate videos: {error_msg}
Error message
Failed to concatenate videos: {error_msg} What it means
_concat_demuxer runs ffmpeg with the concat demuxer (-f concat -safe 0 -i filelist). If the ffmpeg subprocess fails, ffmpeg-python raises ffmpeg.Error, and this handler wraps its stderr into a RuntimeError with the 'Failed to concatenate videos' prefix. The actual cause is in the captured FFmpeg stderr text.
Source
Thrown at pixelle_video/services/video.py:203
escaped_path = str(abs_path).replace("'", "'\\''")
f.write(f"file '{escaped_path}'\n")
filelist = f.name
try:
logger.debug(f"Created filelist: {filelist}")
(
ffmpeg
.input(filelist, format='concat', safe=0)
.output(output, c='copy')
.overwrite_output()
.run(capture_stdout=True, capture_stderr=True)
)
logger.success(f"Videos concatenated successfully: {output}")
return output
except ffmpeg.Error as e:
error_msg = e.stderr.decode() if e.stderr else str(e)
logger.error(f"FFmpeg concat error: {error_msg}")
raise RuntimeError(f"Failed to concatenate videos: {error_msg}")
finally:
if os.path.exists(filelist):
os.unlink(filelist)
def _concat_filter(self, videos: List[str], output: str) -> str:
"""
Concatenate using concat filter (slower but handles different formats)
FFmpeg equivalent:
ffmpeg -i v1.mp4 -i v2.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]"
-map "[v]" -map "[a]" output.mp4
"""
try:
# Build filter_complex string manually
n = len(videos)
# Build input stream labels: [0:v][0:a][1:v][1:a]...
stream_spec = "".join([f"[{i}:v][{i}:a]" for i in range(n)])View on GitHub (pinned to 848b054e4f)
Solutions
- Read the FFmpeg stderr in the exception message — it names the failing input or codec issue.
- Verify every path in `videos` exists and is a valid, readable media file (`ffprobe` each one).
- Ensure all inputs share codec, resolution, and timebase, or force re-encoding (the concat filter path) instead of the stream-copy demuxer.
- Re-encode/re-export problem inputs to a uniform format (e.g. h264/aac mp4) before concatenating.
Example fix
// before
service.concat_videos(['a.mp4', 'b.webm'], 'out.mp4') # demuxer fails: codec mismatch
// after
# normalize inputs first, then concat
for f in ['a.mp4', 'b.webm']:
normalize_to_h264_mp4(f)
service.concat_videos(['a.mp4', 'b.mp4'], 'out.mp4') Defensive patterns
Strategy: try-catch
Validate before calling
for v in videos:
assert os.path.isfile(v), f'missing input: {v}'
import ffmpeg as ff
info = ff.probe(v)
assert info['streams'], f'no streams in {v}' Type guard
def is_valid_media(path: str) -> bool:
try:
return bool(ffmpeg.probe(path).get('streams'))
except Exception:
return False Try / catch
try:
service.concat_videos(videos, out)
except RuntimeError as e:
if 'Failed to concatenate videos' in str(e):
logger.error(f'ffmpeg concat demuxer failed: {e}')
# inspect stderr in message; re-encode inputs or fall back to filter concat
else:
raise Prevention
- Normalize all inputs to the same codec/resolution/timebase (h264+aac mp4) before concat.
- ffprobe every input in CI before running long concat jobs.
- Keep intermediate segment files alive until concat completes (no premature temp cleanup).
- Avoid exotic codecs/containers for intermediates.
When it happens
Trigger: Files listed in the filelist do not exist or are unreadable; inputs have mismatched codecs/resolutions/timebases that the demuxer cannot concat; `-safe 0` omitted for absolute paths (not in this implementation, but path quoting issues); corrupted or non-media files passed as inputs.
Common situations: Concatenating clips from different sources/encoders; a temp segment was deleted before concatenation; files with non-ASCII paths mishandled; codec mismatch (h264 vs vp9) requiring re-encode via the filter method instead.
Related errors
- Failed to concatenate videos: {e}
- Failed to trim video: {error_msg}
- Failed to pad video: {error_msg}
- FFmpeg not found. Please install it: macOS: brew install f
- Failed to add audio to video: {error_msg}
AI-assisted analysis of ATH-MaaS/Pixelle-Video@848b054e4f (2026-08-30).
Data as JSON: /api/errors/e2c96f594687bd3c.
Report an issue: GitHub.