screenpipe/screenpipe · error · anyhow::Error
export produced an empty file
Error message
export produced an empty file
What it means
After running the ffmpeg mux pipeline, the export routine stats the output MP4 and rejects it if its size is 0 bytes. An empty output means the mux produced no data — usually ffmpeg ran 'successfully' but consumed no valid frames/audio inputs. This is a post-flight sanity check so callers never receive a corrupt/empty file path.
Source
Thrown at crates/screenpipe-engine/src/meeting_export.rs:385
tokio::fs::write(&concat_path, concat_body)
.await
.context("failed to write concat list")?;
if let Some(parent) = output_path.parent() {
tokio::fs::create_dir_all(parent)
.await
.with_context(|| format!("failed to create output dir {}", parent.display()))?;
}
// 8. Single ffmpeg mux: concat (video) + N audio inputs → re-timed video + mixed audio.
run_mux(&ffmpeg_path, &concat_path, &audio, origin, output_path).await?;
let file_size_bytes = tokio::fs::metadata(output_path)
.await
.map(|m| m.len())
.unwrap_or(0);
if file_size_bytes == 0 {
return Err(anyhow!("export produced an empty file"));
}
let summary = MeetingExportSummary {
output_path: output_path.to_string_lossy().to_string(),
frame_count: surviving.len(),
audio_chunk_count: audio.len(),
duration_secs: timeline_end,
file_size_bytes,
};
info!(
"export complete: {} frames, {} audio chunks, {:.1}s, {} bytes -> {}",
summary.frame_count,
summary.audio_chunk_count,
summary.duration_secs,
summary.file_size_bytes,
summary.output_path
);
Ok(summary)View on GitHub (pinned to 4ebf712990)
Solutions
- Check that surviving frames reference existing, non-empty source video files before calling export (disk existence + size > 0).
- Widen the requested time range or reduce filtering so at least one frame survives export.
- Verify free disk space and write permissions on output_path.
- Run the export again with ffmpeg stderr logging enabled to see warnings from the mux steps.
Example fix
// before
let summary = export_range_to_mp4(&state, range, out_path).await?;
// after
if !range_has_surviving_frames(&state, &range).await? {
return Err(anyhow!("no frames in the requested range; nothing to export"));
}
let summary = export_range_to_mp4(&state, range, out_path).await?; Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
fn validate_export_inputs(frames: &[FrameRef]) -> Result<(), String> {
if frames.is_empty() { return Err("no frames in range".into()); }
for f in frames {
let p = Path::new(&f.video_path);
match std::fs::metadata(p) {
Ok(m) if m.len() > 0 => {}
Ok(_) => return Err(format!("empty source video: {}", f.video_path)),
Err(_) => return Err(format!("missing source video: {}", f.video_path)),
}
}
Ok(())
} Prevention
- Pre-check that every frame's source video exists and is non-empty before exporting.
- Reject time ranges that filter down to zero frames.
- Check free disk space on the output volume before starting an export.
- Log ffmpeg stderr during export to diagnose empty-output runs.
When it happens
Trigger: Calling export_range_to_mp4 or export_range_to_mp4_video_only when the selected frame range has no surviving frames, all source video files referenced by the frames are missing or truncated (0-byte), or ffmpeg's concat/mux steps produced an output file that was never written (e.g. disk full or output path unwritable so metadata.len() is 0).
Common situations: User asks to export a meeting window that was pruned to zero frames after dedup/snapshot filtering; video files were deleted by retention/cleanup before export; output disk ran out of space mid-write; output path points to a directory or locked file so ffmpeg wrote nothing.
Related errors
- ffmpeg {what} failed: {}
- failed to extract frame: no data received
- ffmpeg missing after unpack at {}
- couldn't find home directory
- ffmpeg not found
AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01).
Data as JSON: /api/errors/e5f21cf6e565a0a2.
Report an issue: GitHub.