{"record":{"id":"7464408b2ebbeb83","repo":"SubtitleEdit/subtitleedit","slug":"moss-tts-crispasr-model-filename-failed-integr","errorCode":null,"errorMessage":"MOSS-TTS (CrispASR) model {fileName} failed integrity check (expected SHA-256 {expected}, got {actual}).","messagePattern":"MOSS-TTS \\(CrispASR\\) model (.+?) failed integrity check \\(expected SHA-256 (.+?), got (.+?)\\)\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Download/MossTtsCrispAsrDownloadService.cs","lineNumber":145,"sourceCode":"        {\n            return;\n        }\n\n        var expected = DownloadHashManager.GetLatestKnownHash(key);\n        if (string.IsNullOrEmpty(expected))\n        {\n            return;\n        }\n\n        string actual;\n        await using (var stream = File.OpenRead(filePath))\n        {\n            actual = await Sha256Util.ComputeSha256Async(stream, cancellationToken);\n        }\n\n        if (!string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase))\n        {\n            throw new IOException(\n                $\"MOSS-TTS (CrispASR) model {fileName} failed integrity check (expected SHA-256 {expected}, got {actual}).\");\n        }\n    }\n\n    private static string GetUrl(string fileName)\n    {\n        if (!ModelUrls.TryGetValue(fileName, out var url))\n        {\n            throw new ArgumentException($\"Unknown MOSS-TTS (CrispASR) model: {fileName}\", nameof(fileName));\n        }\n        return url;\n    }\n\n    private static void TryDelete(string path)\n    {\n        try { File.Delete(path); } catch { /* best-effort cleanup */ }\n    }\n","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Download/MossTtsCrispAsrDownloadService.cs#L127-L163","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Delete the cached file at the model path and re-run the download so it is fetched fresh.","Confirm the pinned expected SHA-256 in the service matches the artifact the origin actually serves (the publisher may have republished the file).","Verify network/disk health: a flaky connection or full disk can truncate the file and flip the hash.","If the model was intentionally republished, update the pinned hash constant in MossTtsCrispAsrDownloadService and ship a new build."],"exampleFix":"// before\nif (!string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase))\n{\n    throw new IOException($\"MOSS-TTS (CrispASR) model {fileName} failed integrity check ...\");\n}\n\n// after - retry once after deleting the suspect cached file, then surface a clearer failure\nif (!string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase))\n{\n    File.Delete(filePath);\n    throw new IOException(\n        $\"MOSS-TTS (CrispASR) model {fileName} failed integrity check \" +\n        $\"(expected {expected}, got {actual}). The cached file was removed; retry the download.\");\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check: if a cached file exists, verify its hash before offering it as ready.\nvar cached = Path.Combine(modelFolder, fileName);\nif (File.Exists(cached))\n{\n    using var s = File.OpenRead(cached);\n    var h = await Sha256Util.ComputeSha256Async(s, ct);\n    if (!string.Equals(expected, h, StringComparison.OrdinalIgnoreCase))\n    {\n        File.Delete(cached); // stale/corrupt; force re-download\n    }\n}","typeGuard":null,"tryCatchPattern":"try { await downloadService.DownloadModelAsync(...); }\ncatch (IOException ex) when (ex.Message.Contains(\"failed integrity check\"))\n{\n    // delete suspect cache, retry once, then surface a clear user message\n    if (File.Exists(filePath)) File.Delete(filePath);\n    await downloadService.DownloadModelAsync(...);\n}","preventionTips":["Always clear the model cache before re-downloading after a version bump.","Keep the pinned expected hash and the origin artifact in lockstep when republishing.","Wrap downloads in retry-with-backoff bounded to a small count to absorb transient corruption."],"tags":["integrity-check","sha256","download","moss-tts","csharp"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}