{"record":{"id":"236c2c12f6239ae7","repo":"SubtitleEdit/subtitleedit","slug":"ffmpeg-failed-to-extract-chunk-i-1-boundaries","errorCode":null,"errorMessage":"ffmpeg failed to extract chunk {i + 1}/{boundaries.Count} ({boundary.StartSeconds:0.##}s → {boundary.EndSeconds:0.##}s) from {audioFileName}","messagePattern":"ffmpeg failed to extract chunk (.+?)/(.+?) \\((.+?)s → (.+?)s\\) from (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/SpeechToText/SpeechToTextViewModel.cs","lineNumber":1601,"sourceCode":"\n            var boundary = boundaries[i];\n            var chunkPath = Path.Combine(GetSttTempFolder(), $\"se-stt-chunk-{Guid.NewGuid()}{extension}\");\n            // Register before extraction so a throw mid-extract still drains\n            // the (possibly partial) file via the outer _filesToDelete sweep.\n            _filesToDelete.Add(chunkPath);\n\n            LogToConsole(\n                $\"Chunk {i + 1}/{boundaries.Count}: \" +\n                $\"{TimeSpan.FromSeconds(boundary.StartSeconds):mm\\\\:ss} → {TimeSpan.FromSeconds(boundary.EndSeconds):mm\\\\:ss}\");\n\n            try\n            {\n                var extractOk = await OpenAiSttChunker.ExtractChunkAsync(\n                    ffmpegPath, audioFileName, chunkPath,\n                    boundary.StartSeconds, boundary.DurationSeconds, cancellationToken);\n                if (!extractOk)\n                {\n                    throw new InvalidOperationException(\n                        $\"ffmpeg failed to extract chunk {i + 1}/{boundaries.Count} \" +\n                        $\"({boundary.StartSeconds:0.##}s → {boundary.EndSeconds:0.##}s) from {audioFileName}\");\n                }\n\n                // Wrap the caller's segment progress so streaming segments coming\n                // from this chunk get offset back to absolute time before the UI\n                // sees them.\n                var offsetSeconds = boundary.StartSeconds;\n                var offsettingProgress = new Progress<OpenAiCompatibleSegment>(seg =>\n                {\n                    segmentProgress.Report(new OpenAiCompatibleSegment\n                    {\n                        Id = seg.Id,\n                        Start = seg.Start + offsetSeconds,\n                        End = seg.End + offsetSeconds,\n                        Text = seg.Text,\n                    });\n                });","sourceCodeStart":1583,"sourceCodeEnd":1619,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/SpeechToText/SpeechToTextViewModel.cs#L1583-L1619","documentation":"OpenAiSttChunker.ExtractChunkAsync returned false (ffmpeg exited non-zero), so the chunk WAV for the i-th boundary was not produced. The ViewModel surfaces it as InvalidOperationException naming the chunk index, the start/end seconds, and the source audio file.","triggerScenarios":"ffmpegPath does not resolve to a working ffmpeg; audioFileName is missing/corrupt/undecodable; boundary.StartSeconds/EndSeconds are out of range or produce zero/negative DurationSeconds; output chunkPath is on a non-writable directory.","commonSituations":"ffmpeg not installed or moved after settings saved; truncated audio file; rounding errors producing 0-length chunks at the very start/end of short clips; permissions on the temp chunk folder.","solutions":["Confirm ffmpegPath resolves to a working ffmpeg binary (run `ffmpeg -version`).","Verify audioFileName exists and is decodable.","Check boundary.StartSeconds/DurationSeconds produce a positive, in-range duration.","Run the exact ffmpeg command ExtractChunkAsync builds, manually, to read the underlying stderr."],"exampleFix":"// before: pass boundaries without sanity-checking\n// after: skip degenerate boundaries before extracting\nif (boundary.DurationSeconds <= 0 || boundary.EndSeconds > totalAudioSeconds)\n{\n    LogToConsole($\"Skipping degenerate chunk {i + 1}\");\n    continue;\n}","handlingStrategy":"validation","validationCode":"if (!File.Exists(ffmpegPath)) return Invalid(\"ffmpeg not found at \" + ffmpegPath);\nif (!File.Exists(audioFileName)) return Invalid(\"audio file missing\");\nif (boundary.DurationSeconds <= 0) return Invalid(\"zero-length chunk\");","typeGuard":null,"tryCatchPattern":"try { extractOk = await OpenAiSttChunker.ExtractChunkAsync(...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"ffmpeg failed to extract chunk\"))\n{ /* log chunk index + boundary, continue or abort the run */ }","preventionTips":["Validate ffmpegPath at engine startup, not per chunk.","Sanity-check boundary ranges against total audio duration before extracting.","Run the exact ffmpeg command manually when extraction fails to read stderr."],"tags":["ffmpeg","audio","chunking","speech-to-text"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}