SubtitleEdit/subtitleedit · error · IOException

MOSS-TTS (CrispASR) model {fileName} failed integrity check

Error message

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

What it means

Thrown by MOSS-TTS CrispASR download service after a model file is downloaded and its SHA-256 hash does not match the expected pinned hash. It is an IOException raised by an integrity gate that runs over the freshly downloaded (or cached) file before it is allowed into the model registry.

Source

Thrown at src/ui/Logic/Download/MossTtsCrispAsrDownloadService.cs:145

        {
            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(
                $"MOSS-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 MOSS-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. Delete the cached file at the model path and re-run the download so it is fetched fresh.
  2. Confirm the pinned expected SHA-256 in the service matches the artifact the origin actually serves (the publisher may have republished the file).
  3. Verify network/disk health: a flaky connection or full disk can truncate the file and flip the hash.
  4. If the model was intentionally republished, update the pinned hash constant in MossTtsCrispAsrDownloadService and ship a new build.

Example fix

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

// after - retry once after deleting the suspect cached file, then surface a clearer failure
if (!string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase))
{
    File.Delete(filePath);
    throw new IOException(
        $"MOSS-TTS (CrispASR) model {fileName} failed integrity check " +
        $"(expected {expected}, got {actual}). The cached file was removed; retry the download.");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: if a cached file exists, verify its hash before offering it as ready.
var cached = Path.Combine(modelFolder, fileName);
if (File.Exists(cached))
{
    using var s = File.OpenRead(cached);
    var h = await Sha256Util.ComputeSha256Async(s, ct);
    if (!string.Equals(expected, h, StringComparison.OrdinalIgnoreCase))
    {
        File.Delete(cached); // stale/corrupt; force re-download
    }
}

Try / catch

try { await downloadService.DownloadModelAsync(...); }
catch (IOException ex) when (ex.Message.Contains("failed integrity check"))
{
    // delete suspect cache, retry once, then surface a clear user message
    if (File.Exists(filePath)) File.Delete(filePath);
    await downloadService.DownloadModelAsync(...);
}

Prevention

When it happens

Trigger: ComputeSha256Async runs over the downloaded file at filePath; expected is the pinned value from the service's hash table. The check is skipped (returns early) only when expected is empty, so a populated-but-wrong hash always throws this IOException.

Common situations: A truncated or partially written download (network drop, disk full), a CDN/origin that silently swapped the model artifact without bumping the pinned hash, a corrupt local cache from a previous interrupted run, or bit-rot on disk.

Related errors


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