SubtitleEdit/subtitleedit · error · FileNotFoundException
yt-dlp finished but no video file was produced. Temp directo
Error message
yt-dlp finished but no video file was produced.
Temp directory: {tempDir}
Contents: {files} What it means
Thrown when yt-dlp exits without error but FindProducedVideo cannot locate any valid video file in the temp directory. FindProducedVideo enumerates files matching 'download.*', excluding subtitle sidecars (names with two dots like 'download.en.srt') and incomplete '.part' files. If nothing remains, the download is treated as failed despite yt-dlp reporting success.
Source
Thrown at src/ui/Features/Video/OpenFromUrl/DownloadVideoFromUrlViewModel.cs:169
// Pass yt-dlp the literal "%(ext)s" placeholder so it picks the actual
// container extension. If we use the user's chosen extension verbatim
// (e.g. "download.mkv"), yt-dlp treats the whole thing as the template
// stem and writes "download.mkv.webm" after the merge — leaving us
// unable to find the produced file by predicted name.
var templatePath = Path.Combine(tempDir, "download.%(ext)s");
try
{
await _ytDlpDownloadService.DownloadVideo(_url, templatePath, _downloadSubtitles, progress, cancellationToken, stageProgress);
// Everything from here on is silent too: moving the file out of the temp dir can
// be a full copy across volumes, and the auto-caption fetch is another yt-dlp run.
stageProgress.Report(YtDlpDownloadStage.PostProcessing);
var actualVideoPath = FindProducedVideo(tempDir);
if (actualVideoPath is null)
{
throw new FileNotFoundException(
"yt-dlp finished but no video file was produced." + Environment.NewLine +
$"Temp directory: {tempDir}" + Environment.NewLine +
"Contents: " + (Directory.Exists(tempDir)
? string.Join(", ", Directory.EnumerateFiles(tempDir).Select(Path.GetFileName))
: "<missing>"));
}
if (File.Exists(OutputPath))
{
File.Delete(OutputPath);
}
File.Move(actualVideoPath, OutputPath);
if (_downloadSubtitles)
{
if (_includeAutoGeneratedSubtitles)
{
tryView on GitHub (pinned to 17a9f07487)
Solutions
- Check the temp directory contents listed in the error message to see what yt-dlp actually wrote.
- Verify ffmpeg/ffprobe is installed and on PATH — yt-dlp needs it for merging separate audio/video streams.
- Update yt-dlp to the latest version (yt-dlp self-update or reinstall).
- Test the URL directly with yt-dlp from the command line using the same -o template to see what filename it produces.
- If the URL is audio-only, use an audio download flow instead of video.
- Check yt-dlp's --verbose output for merge failures or post-processing errors.
Example fix
// before
var actualVideoPath = FindProducedVideo(tempDir);
if (actualVideoPath is null)
{
throw new FileNotFoundException(
"yt-dlp finished but no video file was produced." + Environment.NewLine +
$"Temp directory: {tempDir}" + Environment.NewLine +
"Contents: " + (Directory.Exists(tempDir)
? string.Join(", ", Directory.EnumerateFiles(tempDir).Select(Path.GetFileName))
: "<missing>"));
}
// after — broaden the search and include yt-dlp's own output in the message
var actualVideoPath = FindProducedVideo(tempDir);
if (actualVideoPath is null)
{
// Fall back: accept any non-subtitle, non-part file in the temp dir
var allFiles = Directory.Exists(tempDir)
? Directory.EnumerateFiles(tempDir).ToList()
: new List<string>();
actualVideoPath = allFiles.FirstOrDefault(f =>
{
var ext = Path.GetExtension(f).ToLowerInvariant();
return !new[] { ".srt", ".vtt", ".ass", ".ssa", ".sub", ".part" }.Contains(ext);
});
}
if (actualVideoPath is null)
{
throw new FileNotFoundException(
"yt-dlp finished but no video file was produced." + Environment.NewLine +
$"Temp directory: {tempDir}" + Environment.NewLine +
"Contents: " + (Directory.Exists(tempDir)
? string.Join(", ", Directory.EnumerateFiles(tempDir).Select(Path.GetFileName))
: "<missing>"));
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate the URL with yt-dlp's --simulate flag
var psi = new ProcessStartInfo("yt-dlp", $"--simulate --no-warnings \"{_url}\"")
{ RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false };
using var proc = Process.Start(psi);
await proc.WaitForExitAsync();
if (proc.ExitCode != 0)
throw new InvalidOperationException("yt-dlp cannot resolve URL: " + _url); Try / catch
try { await _ytDlpDownloadService.DownloadVideo(...); }
catch (FileNotFoundException ex) when (ex.Message.Contains("no video file was produced"))
{ /* read temp dir contents from message, check for .part files (incomplete), suggest ffmpeg install or retry */ } Prevention
- Ensure ffmpeg and ffprobe are installed and on PATH — yt-dlp requires them for merging audio/video streams.
- Keep yt-dlp updated to the latest version.
- Test URLs with yt-dlp CLI before relying on the programmatic wrapper.
- Avoid URLs that are known to be audio-only or stream-only without downloadable video.
When it happens
Trigger: yt-dlp writes the final file with a name that doesn't match 'download.*' (e.g. it used a different template stem); yt-dlp wrote only subtitle files and no video; the merge step failed silently leaving only .part files; the output was written to a different directory than tempDir; yt-dlp completed but the temp directory was concurrently cleaned.
Common situations: yt-dlp version upgrade changed default output naming behaviour; the URL is audio-only or subtitle-only with no video stream; yt-dlp's merge step (e.g. ffmpeg) is missing and it leaves fragmented .part files; the template path with %(ext)s was overridden by yt-dlp config; a concurrent cleanup process removed the temp dir.
Related errors
- Downloaded yt-dlp ({assetName}) failed SHA-256 verification
- yt-dlp exited with code {process.ExitCode}.
- yt-dlp subtitle download exited with code {process.ExitCode}
- NameList: Unable to read name list file: {fileNameOrUrl}
- Baidu API Error {errorCode}: {errorMsg}
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/d5952adccb7aa5e7.
Report an issue: GitHub.