{"record":{"id":"0ba435757f399ce7","repo":"SubtitleEdit/subtitleedit","slug":"error","errorCode":null,"errorMessage":"{error}","messagePattern":"\\{error\\}","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/VideoOcr/VideoOcrViewModel.cs","lineNumber":1053,"sourceCode":"        Func<VideoOcrFrameGroup, Task<string>> ocr,\n        Func<string> getError,\n        Action reportProgress,\n        Action<VideoOcrFrameGroup> addPreviewLine,\n        CancellationToken cancellationToken)\n    {\n        var isFirst = true;\n        foreach (var group in ocrGroups)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            group.Text = VideoOcrLineBuilder.CleanOcrResult(await ocr(group));\n\n            // Fail fast on a broken engine (wrong API key/URL) instead of grinding\n            // through the whole video and reporting \"no subtitles found\".\n            var error = getError();\n            if (isFirst && string.IsNullOrEmpty(group.Text) && !string.IsNullOrEmpty(error))\n            {\n                throw new Exception(error);\n            }\n\n            isFirst = false;\n            reportProgress();\n            addPreviewLine(group);\n        }\n    }\n\n    private async Task<bool> EnsureEngineIsAvailable()\n    {\n        var engineType = SelectedEngine.EngineType;\n\n        if (engineType == OcrEngineType.Glm && string.IsNullOrWhiteSpace(GlmApiKey))\n        {\n            await MessageBox.Show(\n                Window!,\n                Se.Language.General.Error,\n                \"An API key is required for the GLM API engine.\",","sourceCodeStart":1035,"sourceCodeEnd":1071,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/VideoOcr/VideoOcrViewModel.cs#L1035-L1071","documentation":"Thrown inside RunLlmOcr as a fail-fast guard: on the FIRST group only, if the OCR call returned empty text AND the engine's getError() is non-empty, the scan aborts immediately instead of grinding through every frame and reporting 'no subtitles found'. This catches a globally-broken engine early — most commonly a wrong API key or URL for the GLM/Ollama/LlamaCpp backends.","triggerScenarios":"First frame yields no text and the engine reported an error: invalid/missing API key (GLM), wrong base URL, model name not found on the server, network/auth failure, or the inference server returning an error status.","commonSituations":"GLM API key empty or revoked; Ollama/LlamaCpp URL wrong or server not running; model id typo; rate-limit/auth error from the provider; server started but model failed to load.","solutions":["Read the engine.Error text in the exception — it is the backend's own error (auth/model/HTTP).","For GLM: verify the API key is set and valid in settings.","For Ollama/LlamaCpp: confirm the URL is reachable and the named model is loaded (curl the /api/tags or /v1/models endpoint).","Correct the URL/model/key and re-run; only after the first frame succeeds will the rest proceed."],"exampleFix":"// before\nvar error = getError();\nif (isFirst && string.IsNullOrEmpty(group.Text) && !string.IsNullOrEmpty(error))\n    throw new Exception(error);\n\n// after - name the engine and frame so the user knows where it died\nvar error = getError();\nif (isFirst && string.IsNullOrEmpty(group.Text) && !string.IsNullOrEmpty(error))\n    throw new Exception($\"OCR engine error on first frame ({group.RepresentativeFileName}): \" + error);","handlingStrategy":"validation","validationCode":"// Validate credentials/endpoint before the scan for each LLM backend.\nif (engineType == OcrEngineType.Glm && string.IsNullOrWhiteSpace(GlmApiKey)) throw new Exception(\"GLM API key is required.\");\nif (engineType == OcrEngineType.Ollama && !await IsReachable(OllamaUrl)) throw new Exception(\"Ollama server is not reachable.\");","typeGuard":null,"tryCatchPattern":"try { await RunLlmOcr(...); }\ncatch (Exception ex) // fail-fast guard re-throws the engine error\n{\n    SeLogger.Error(ex, \"LLM OCR failed on first frame - check API key/URL/model\");\n    await MessageBox.Show(Window!, Se.Language.General.Error, ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);\n}","preventionTips":["Verify the API key/URL/model before starting the scan.","For Ollama/LlamaCpp, confirm the named model is loaded.","Treat a first-frame empty+error as an auth/config problem, not empty content."],"tags":["ocr","llm-ocr","video-ocr","api-key","network"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}