{"record":{"id":"99dd804d643b376f","repo":"SubtitleEdit/subtitleedit","slug":"se-language-ocr-crispembednotdownloaded","errorCode":null,"errorMessage":"{Se.Language.Ocr.CrispEmbedNotDownloaded}","messagePattern":"\\{Se\\.Language\\.Ocr\\.CrispEmbedNotDownloaded\\}","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/VideoOcr/VideoOcrViewModel.cs","lineNumber":998,"sourceCode":"        }\n    }\n\n    /// <summary>\n    /// Runs the frame groups through CrispEmbed. The VLM backends load the GGUF into one\n    /// crispembed-server instance that stays up for the whole scan - a video produces hundreds of\n    /// groups and the model load alone is seconds, so starting a server per frame would be\n    /// unusable. PP-OCRv6 is a detector+recognizer pair driven through the CLI instead, one\n    /// invocation per frame, which is what <see cref=\"CrispEmbedOcr\"/> expects.\n    /// </summary>\n    private async Task OcrGroupsWithCrispEmbed(\n        List<VideoOcrFrameGroup> ocrGroups,\n        Action reportProgress,\n        Action<VideoOcrFrameGroup> addPreviewLine,\n        CancellationToken cancellationToken)\n    {\n        if (SelectedCrispEmbedBackend is not { } backend || SelectedCrispEmbedModel is not { } model)\n        {\n            throw new Exception(Se.Language.Ocr.CrispEmbedNotDownloaded);\n        }\n\n        using var engine = new CrispEmbedOcr(Se.Settings.Ocr.CrispEmbedOcrTimeoutMinutes);\n\n        var started = backend.UsesTextDetector\n            ? engine.StartCliPipeline(\n                CrispEmbedEngine.GetCliExecutable(),\n                backend.GetModelPath(model.Model),\n                backend.GetDetectorPath(model.Model))\n            : await engine.StartServerAsync(\n                CrispEmbedEngine.GetServerExecutable(),\n                backend.GetModelPath(model.Model),\n                cancellationToken);\n\n        if (!started)\n        {\n            throw new Exception(engine.Error);\n        }","sourceCodeStart":980,"sourceCodeEnd":1016,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/VideoOcr/VideoOcrViewModel.cs#L980-L1016","documentation":"Thrown at the top of OcrGroupsWithCrispEmbed when either SelectedCrispEmbedBackend or SelectedCrispEmbedModel is null — the pattern `is not { } backend || ... is not { } model` fails. With no backend+model selected the method cannot locate an executable or model path, so it aborts immediately with the localized 'CrispEmbedNotDownloaded' message rather than passing nulls into CrispEmbedEngine.GetCliExecutable/GetServerExecutable.","triggerScenarios":"User chose the CrispEmbed OCR engine but never downloaded/selected a backend or model, or a previously selected model was removed and the selection reset to null before the scan started.","commonSituations":"First use of CrispEmbed with nothing downloaded; a model download was interrupted leaving the entry null; the backend/model dropdowns were cleared by a settings reset.","solutions":["Open the CrispEmbed settings and download then select a backend and a model before starting OCR.","Run the EnsureCrispEmbedReady preflight (called from EnsureEngineIsAvailable) so the engine is validated before OcrGroupsWithCrispEmbed is reached.","If a download was interrupted, remove the partial model and re-download."],"exampleFix":"// before\nif (SelectedCrispEmbedBackend is not { } backend || SelectedCrispEmbedModel is not { } model)\n    throw new Exception(Se.Language.Ocr.CrispEmbedNotDownloaded);\n\n// after - block at the command layer so the user gets a guided fix, not a throw\nif (SelectedCrispEmbedBackend is null || SelectedCrispEmbedModel is null)\n{\n    await MessageBox.Show(Window!, Se.Language.General.Error,\n        \"Download and select a CrispEmbed backend and model first.\",\n        MessageBoxButtons.OK, MessageBoxIcon.Error);\n    return;\n}","handlingStrategy":"validation","validationCode":"if (SelectedCrispEmbedBackend is null || SelectedCrispEmbedModel is null)\n{\n    await MessageBox.Show(Window!, Se.Language.General.Error,\n        \"Download and select a CrispEmbed backend and model first.\",\n        MessageBoxButtons.OK, MessageBoxIcon.Error);\n    return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate the Start OCR command on a non-null backend and model.","Run EnsureCrispEmbedReady before OcrGroupsWithCrispEmbed.","Re-download interrupted models fully so selections are never left null."],"tags":["ocr","crispembed","video-ocr","configuration","validation"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}