SubtitleEdit/subtitleedit · error · InvalidOperationException
Downloaded yt-dlp ({assetName}) failed SHA-256 verification
Error message
Downloaded yt-dlp ({assetName}) failed SHA-256 verification — expected {expected}, got {actual}. The file has been removed. What it means
Thrown by VerifyChecksumAsync in YtDlpDownloadService after a yt-dlp download when the computed SHA-256 of the saved file does not match the pinned expected hash in KnownSha256 for that (version, assetName) pair. The corrupted/tampered file is deleted via TryDeleteFile before the throw, so the next attempt re-downloads.
Source
Thrown at src/ui/Logic/Download/YtDlpDownloadService.cs:184
/// checksum for <paramref name="version"/>. A tampered, truncated, or
/// otherwise corrupt download is deleted and surfaced as an error instead
/// of being executed. If no checksum is on record for the asset, this is a
/// no-op — we don't block on data we don't have.
/// </summary>
internal static async Task VerifyChecksumAsync(string filePath, string version, CancellationToken cancellationToken)
{
var assetName = Path.GetFileName(filePath);
if (!KnownSha256.TryGetValue(version, out var byAsset) ||
!byAsset.TryGetValue(assetName, out var expected))
{
return;
}
var actual = await ComputeSha256Async(filePath, cancellationToken);
if (!string.Equals(actual, expected, StringComparison.OrdinalIgnoreCase))
{
TryDeleteFile(filePath);
throw new InvalidOperationException(
$"Downloaded yt-dlp ({assetName}) failed SHA-256 verification — expected {expected}, got {actual}. The file has been removed.");
}
}
internal static async Task<string> ComputeSha256Async(string filePath, CancellationToken cancellationToken)
{
await using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var hash = await SHA256.HashDataAsync(stream, cancellationToken);
return Convert.ToHexString(hash).ToLowerInvariant();
}
private static void TryDeleteFile(string filePath)
{
try
{
if (File.Exists(filePath))
{
File.Delete(filePath);View on GitHub (pinned to 17a9f07487)
Solutions
- Retry the download once — transient truncation/network corruption is the most common cause and the bad file is already removed.
- If it persists, verify your network path is not MITM'd (compare a manual curl SHA against yt-dlp's published checksum).
- Update the KnownSha256 entry to the currently published checksum if upstream re-released the same version.
- Confirm Se.DataFolder is writable and not on a filesystem that silently alters bytes (e.g. encoding conversion).
Example fix
// before
await _ytDlp.DownloadYtDlp(progress, ct);
// after: retry once, then surface a clear message
try
{
await _ytDlp.DownloadYtDlp(progress, ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("SHA-256"))
{
await _ytDlp.DownloadYtDlp(progress, ct); // bad file was auto-deleted; one retry
} Defensive patterns
Strategy: retry
Try / catch
try { await svc.DownloadYtDlp(progress, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("SHA-256 verification"))
{ await svc.DownloadYtDlp(progress, ct); } // one retry; bad file was auto-deleted Prevention
- Keep KnownSha256 in sync with yt-dlp's published checksums after each release.
- Avoid networks/proxies that rewrite binaries.
When it happens
Trigger: A completed yt-dlp download whose bytes differ from the pinned checksum: truncated transfer, transparent proxy/MITM, a mirrored/corrupted release, or a yt-dlp version whose KnownSha256 entry was updated to a newer build than what was downloaded.
Common situations: Corporate proxy that rewrites binaries, a flaky connection that truncated the download, or a stale KnownSha256 table after yt-dlp published a re-tagged release with the same version number.
Related errors
- Zonos TTS (CrispASR) model {fileName} failed integrity check
- CosyVoice3 (CrispASR) model {fileName} failed integrity chec
- F5-TTS (CrispASR) model {fileName} failed integrity check (e
- IndexTTS (CrispASR) model {fileName} failed integrity check
- Kokoro TTS {label} download failed integrity check (expected
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/a9961670b45644b3.
Report an issue: GitHub.