{"record":{"id":"584facd044d23e01","repo":"SubtitleEdit/subtitleedit","slug":"omnivoice-crispasr-model-filename-failed-integ","errorCode":null,"errorMessage":"OmniVoice (CrispASR) model {fileName} failed integrity check (expected SHA-256 {expected}, got {actual}).","messagePattern":"OmniVoice \\(CrispASR\\) model (.+?) failed integrity check \\(expected SHA-256 (.+?), got (.+?)\\)\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Download/OmniVoiceCrispAsrDownloadService.cs","lineNumber":142,"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                $\"OmniVoice (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 OmniVoice (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":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Download/OmniVoiceCrispAsrDownloadService.cs#L124-L160","documentation":"Identical integrity gate to the MOSS-TTS one, but for the OmniVoice CrispASR model set. The OmniVoiceCrispAsrDownloadService computes a SHA-256 over the downloaded model and throws IOException if it diverges from the pinned expected value.","triggerScenarios":"A non-empty expected hash compared case-insensitively against the computed actual hash of the file on disk; mismatch trips the throw. Empty expected short-circuits.","commonSituations":"Partial download, CDN republished the model without updating the pinned hash, corrupt cache, mirrored/proxied download that altered bytes.","solutions":["Clear the cached model file and re-download.","Verify the pinned expected hash against the current origin artifact.","Check for disk/network issues that truncated the write.","If the artifact was intentionally republished, update the hash table in OmniVoiceCrispAsrDownloadService."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"var 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)) File.Delete(cached);\n}","typeGuard":null,"tryCatchPattern":"try { await service.DownloadModelAsync(...); }\ncatch (IOException ex) when (ex.Message.Contains(\"failed integrity check\"))\n{\n    if (File.Exists(filePath)) File.Delete(filePath);\n    await service.DownloadModelAsync(...);\n}","preventionTips":["Delete cached model files after upgrading the download service binary.","Verify the pinned hash matches the published artifact before release.","Use a bounded retry for transient download corruption."],"tags":["integrity-check","sha256","download","omnivoice","csharp"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}