{"record":{"id":"8275787fac32c599","repo":"SubtitleEdit/subtitleedit","slug":"qwen3-tts-crispasr-model-filename-failed-integ","errorCode":null,"errorMessage":"Qwen3 TTS (CrispASR) model {fileName} failed integrity check (expected SHA-256 {expected}, got {actual}).","messagePattern":"Qwen3 TTS \\(CrispASR\\) model (.+?) failed integrity check \\(expected SHA-256 (.+?), got (.+?)\\)\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Download/Qwen3TtsCrispAsrDownloadService.cs","lineNumber":173,"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                $\"Qwen3 TTS (CrispASR) model {fileName} failed integrity check (expected SHA-256 {expected}, got {actual}).\");\n        }\n    }\n\n    private static void TryDelete(string path)\n    {\n        try { File.Delete(path); } catch { /* best-effort cleanup */ }\n    }\n\n    private static void EnsureRemovedIfInvalid(string path, string fileName)\n    {\n        if (!File.Exists(path) || Qwen3TtsCrispAsr.IsValidLocalModelFile(path, fileName))\n        {\n            return;\n        }\n        TryDelete(path);\n    }\n}","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Download/Qwen3TtsCrispAsrDownloadService.cs#L155-L191","documentation":"Integrity check for the Qwen3 TTS CrispASR model set. After download (or on cache validation) the file is opened read-only, hashed, and compared to the pinned expected value; mismatch throws IOException. An invalid file is also cleaned up via EnsureRemovedIfInvalid/IsValidLocalModelFile in the surrounding code.","triggerScenarios":"Non-empty expected hash that differs from the computed SHA-256 of filePath. The surrounding code's TryDelete/EnsureRemovedIfInvalid helpers exist precisely because this mismatch can recur on bad downloads.","commonSituations":"Interrupted prior download left a partial file, CDN republished without hash bump, disk corruption, or a cache that survived a binary update that pinned a new hash.","solutions":["Let EnsureRemovedIfInvalid delete the bad file and re-download.","Manually delete the cached model and retry.","Verify the pinned expected hash matches the current origin artifact.","Check network/disk for truncation."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (File.Exists(filePath) && !Qwen3TtsCrispAsr.IsValidLocalModelFile(filePath, fileName))\n{\n    File.Delete(filePath); // proactively purge invalid cache\n}","typeGuard":null,"tryCatchPattern":"try { await service.DownloadModelAsync(...); }\ncatch (IOException ex) when (ex.Message.Contains(\"failed integrity check\"))\n{\n    TryDelete(filePath);\n    await service.DownloadModelAsync(...);\n}","preventionTips":["Call EnsureRemovedIfInvalid before offering a cached model as ready.","Keep pinned hashes and origin artifacts in sync on republish.","Use a bounded retry for transient download corruption."],"tags":["integrity-check","sha256","download","qwen3-tts","crispasr","csharp"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}