SubtitleEdit/subtitleedit · error · InvalidOperationException

Failed to start paddleocr process.

Error message

Failed to start paddleocr process.

What it means

Thrown when `Process.Start(psi)` returns null on a paddleocr invocation. Per .NET docs Process.Start returns null only when no process resource is started (e.g. the executable resolved to a document and a shell opened it) — with UseShellExecute=false this is effectively unreachable for a real binary, so hitting it usually means the resolved path points to something the OS will not launch as a process.

Source

Thrown at src/seconv/Core/PaddleOcrEngine.cs:93

                ArgumentList = { "ocr", "-i", pngPath, "--lang", Language, "--use_angle_cls", "false" },
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                StandardOutputEncoding = System.Text.Encoding.UTF8,
                StandardErrorEncoding = System.Text.Encoding.UTF8,
                UseShellExecute = false,
                CreateNoWindow = true,
            };

            // StandardOutputEncoding only fixes the decoding side. paddleocr is a Python CLI, and
            // on Windows Python encodes a *redirected* stdout with the ANSI codepage (until UTF-8
            // becomes the default in Python 3.15, PEP 686) - so the producer side must be forced
            // to UTF-8 too, or non-ASCII text still arrives as mojibake. Same env vars the UI's
            // Paddle engine sets.
            psi.EnvironmentVariables["PYTHONIOENCODING"] = "utf-8";
            psi.EnvironmentVariables["PYTHONUTF8"] = "1";

            using var proc = Process.Start(psi)
                ?? throw new InvalidOperationException("Failed to start paddleocr process.");
            // Drain stderr concurrently — paddleocr is chatty on stderr, and reading stdout
            // to completion while stderr fills the pipe buffer would deadlock.
            var stderrTask = proc.StandardError.ReadToEndAsync();
            var stdout = proc.StandardOutput.ReadToEnd();
            proc.WaitForExit();
            if (proc.ExitCode != 0)
            {
                var err = stderrTask.GetAwaiter().GetResult();
                throw new InvalidOperationException($"paddleocr exited with code {proc.ExitCode}: {err}");
            }
            return ParseStdout(stdout);
        }
        finally
        {
            try { File.Delete(pngPath); } catch { /* best-effort */ }
        }
    }

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Ensure the paddleocr file is executable: `chmod +x $(which paddleocr)`.
  2. Reinstall paddleocr cleanly so the executable bit is set by pip.
  3. Check that the file at the detected path is the real launcher, not a text stub.
  4. Run `paddleocr --help` manually in the same shell to confirm it launches.

Example fix

# before
ls -l $(which paddleocr)   # -rw-r--r-- (no x bit)
# after
chmod +x $(which paddleocr)
seconv in.sup out.srt --ocr-engine paddle
Defensive patterns

Strategy: validation

Validate before calling

var paddlePath = PaddleOcrEngine.Detect();
if (paddlePath is null) throw new InvalidOperationException("paddleocr missing");
if (OperatingSystem.IsLinux() && !HasExecuteBit(paddlePath))
    throw new InvalidOperationException("paddleocr not executable: chmod +x " + paddlePath);

static bool HasExecuteBit(string p) => (new System.IO.FileInfo(p).UnixMode & System.IO.UnixFileMode.UserExecute) != 0;

Type guard

static bool IsExecutableOnPath(string name) =>
    PaddleOcrEngine.Detect() is { } p && OperatingSystem.IsWindows() ? true : HasExecuteBit(p);

Try / catch

try { var engine = PaddleOcrEngine.Create(lang); }
catch (InvalidOperationException ex) when (ex.Message == "Failed to start paddleocr process.")
{
    // chmod +x, reinstall paddleocr, or fall back
}

Prevention

When it happens

Trigger: PaddleOcrEngine.Recognize invoking Process.Start where Detect() returned a path that is not an executable (a script without a shebang on Unix, a non-executable file, or a path whose execute bit is unset).

Common situations: The paddleocr file exists on PATH but lacks the executable bit (chmod -x); a stub/placeholder file shadowing the real binary; filesystem permission issue.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/832cba5279e09319. Report an issue: GitHub.