SubtitleEdit/subtitleedit · error · IOException

Zonos TTS (CrispASR) model {fileName} failed integrity check

Error message

Zonos TTS (CrispASR) model {fileName} failed integrity check (expected SHA-256 {expected}, got {actual}).

What it means

Thrown by ZonosTtsCrispAsrDownloadService.VerifyFile when the SHA-256 of a freshly downloaded Zonos TTS model (the q8_0 transformer or the DAC codec) does not match the pinned expected hash from DownloadHashManager. Unlike yt-dlp (error 369, which auto-deletes), here the .part file cleanup happens in the DownloadAndVerify catch, and the exception type is IOException. The mismatch signals truncation, corruption, or a mirror that served different bytes.

Source

Thrown at src/ui/Logic/Download/ZonosTtsCrispAsrDownloadService.cs:130

        {
            return;
        }

        var expected = DownloadHashManager.GetLatestKnownHash(key);
        if (string.IsNullOrEmpty(expected))
        {
            return;
        }

        string actual;
        await using (var stream = File.OpenRead(filePath))
        {
            actual = await Sha256Util.ComputeSha256Async(stream, cancellationToken);
        }

        if (!string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase))
        {
            throw new IOException(
                $"Zonos TTS (CrispASR) model {fileName} failed integrity check (expected SHA-256 {expected}, got {actual}).");
        }
    }

    private static string GetUrl(string fileName)
    {
        if (!ModelUrls.TryGetValue(fileName, out var url))
        {
            throw new ArgumentException($"Unknown Zonos TTS (CrispASR) model: {fileName}", nameof(fileName));
        }
        return url;
    }

    private static void TryDelete(string path)
    {
        try { File.Delete(path); } catch { /* best-effort cleanup */ }
    }

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Retry the download once — the .part file is deleted on failure so the next attempt is clean.
  2. If it persists, download the .gguf manually from the Hugging Face URL in ModelUrls and verify its SHA-256 against the published value, then place it at the expected path.
  3. Confirm the pinned hash in DownloadHashManager.ZonosTtsCrispAsr matches the current upstream release.
  4. Check for a corporate proxy altering file bytes.

Example fix

// before
await _zonos.DownloadModels(folder, progress, titleProgress, ct);

// after: one retry on integrity failure
try { await _zonos.DownloadModels(folder, progress, titleProgress, ct); }
catch (IOException ex) when (ex.Message.Contains("failed integrity check"))
{
    await _zonos.DownloadModels(folder, progress, titleProgress, ct);
}
Defensive patterns

Strategy: retry

Try / catch

try { await svc.DownloadModels(folder, progress, titleProgress, ct); }
catch (IOException ex) when (ex.Message.Contains("failed integrity check"))
{ await svc.DownloadModels(folder, progress, titleProgress, ct); } // .part was cleaned; one retry

Prevention

When it happens

Trigger: After DownloadHelper downloads the talker or codec .gguf to a .part file, ComputeSha256Async diverges from DownloadHashManager.GetLatestKnownHash(key). Causes: truncated download, MITM/proxy, partial write, or an updated model whose hash was not yet pinned.

Common situations: Hugging Face mirror serving a re-quantized file; a large (~1.8GB) talker model truncated by a dropped connection; the pinned hash in DownloadHashManager out of date after an upstream re-release.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/4a85d35794c9cea8. Report an issue: GitHub.