screenpipe/screenpipe · error
VIDEO_CORRUPTED: file too small ({} bytes) {}
Error message
VIDEO_CORRUPTED: file too small ({} bytes) {} What it means
Files smaller than 1024 bytes cannot hold a valid video container (no moov/ftyp atoms of substance), so the function treats them as corrupted before wasting an ffmpeg spawn, using the same VIDEO_CORRUPTED prefix mapped to 410 by the HTTP route.
Source
Thrown at crates/screenpipe-engine/src/video_utils.rs:1122
pub async fn extract_frame_from_video(
file_path: &str,
offset_index: i64,
jpeg_quality: &str,
) -> Result<String> {
if offset_index < 0 {
return Err(anyhow::anyhow!(
"invalid negative frame index: {}",
offset_index
));
}
let metadata = ensure_regular_media_file(file_path).await?;
if metadata.len() == 0 {
return Err(anyhow::anyhow!("VIDEO_CORRUPTED: empty file {}", file_path));
}
// Files under 1KB are likely corrupted (no valid video that small).
if metadata.len() < 1024 {
return Err(anyhow::anyhow!(
"VIDEO_CORRUPTED: file too small ({} bytes) {}",
metadata.len(),
file_path
));
}
let ffmpeg_path =
find_ffmpeg_path().ok_or_else(|| anyhow::anyhow!("failed to find ffmpeg path"))?;
// A file whose metadata will not parse is still worth one extraction
// attempt, but if that attempt also fails the file is unreadable rather
// than merely awkward — the route maps that to 410 instead of 500.
let metadata = probe_frame_metadata(&ffmpeg_path, file_path).await?;
let metadata_unreadable = metadata.is_none();
let locator = plan_frame_locator(file_path, offset_index, metadata);
// Create a temporary directory for frames if it doesn't exist
let frames_dir = PathBuf::from("/tmp/screenpipe_frames");View on GitHub (pinned to 4ebf712990)
Solutions
- Delete/quarantine the undersized file; it is unrecoverable as video
- Regenerate the segment by re-recording
- Investigate the writer path (disk space, abrupt shutdown) if many such files appear
- Sweep the media directory at startup for files < 1KB
Defensive patterns
Strategy: validation
Validate before calling
fn looks_like_video(path: &str) -> bool {
std::fs::metadata(path).map(|m| m.len() >= 1024).unwrap_or(false)
} Try / catch
match extract_frame_from_video(&path, idx, "2").await {
Ok(jpeg) => jpeg,
Err(e) if e.to_string().starts_with("VIDEO_CORRUPTED") => None, // mark file dead
Err(e) => return Err(e),
} Prevention
- Treat any media file < 1KB as garbage and prune it proactively
- Check write completion (fsync/close) before exposing segments to extraction
- Monitor truncation causes: power loss, OOM kills, disk pressure
- Regenerate affected segments rather than retrying extraction
When it happens
Trigger: extract_frame_from_video (or its callers generate_thumbnail / try_extract_and_serve_frame / run_frame_ocr) is given a regular file whose metadata.len() is between 1 and 1023 bytes.
Common situations: Same truncation causes as the empty-file case but partially written: crash after writing only the header, interrupted flush, tiny placeholder files from a sync client.
Related errors
- VIDEO_CORRUPTED: empty file {}
- legacy video source is missing or corrupt
- {} already exists but does not contain a valid token
- video file does not exist: {}
- extracted frame has no filename
AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01).
Data as JSON: /api/errors/e9763b66ef8b1f50.
Report an issue: GitHub.