apache/seatunnel · error · IOException

Timed out waiting for Python source stdout to close after…

Error message

Timed out waiting for Python source stdout to close after the process exited; ensure child processes do not inherit stdout

What it means

After the Python process exits, the source waits for the stdout pump thread to drain and close. If stdout is still open past the deadline, a child process inherited the stdout pipe, keeping it open forever; the reader throws this timeout error instead of hanging.

Solutions

  1. Fix the Python script so child processes redirect/close stdout/stderr (subprocess.Popen(..., stdout=DEVNULL) or pass close_fds=True)
  2. Ensure spawned workers use their own pipes/queues rather than the parent's stdout protocol channel
  3. As a workaround, suppress or detach children (daemonize with os.setsid) so stdout EOF arrives when the main process exits

Example fix

# before: children inherit stdout, blocking EOF
cmd = ["worker"]
subprocess.Popen(cmd)
# after
subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, close_fds=True)
Defensive patterns

Strategy: try-catch

Validate before calling

# audit your Python source for child processes that inherit stdout
import subprocess, sys
subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, close_fds=True)

Try / catch

try {
    reader.awaitTermination();
} catch (Exception e) {
    if (e.getMessage().contains("stdout to close")) {
        // fix the Python script's child process stdio handling and rerun
    }
    throw e;
}

Prevention

When it happens

Trigger: Python source process spawns child processes (workers, subprocess.Popen without stdout redirect) that inherit the parent's stdout; stdout pump thread never sees EOF before stdoutCloseDeadlineNanos elapses.

Common situations: Python scripts using multiprocessing/Dask/Spark-like children; invoking shell commands from the Python source that inherit descriptors; long-lived daemons forked by the script.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/7e118d3dff244176. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceReader.java:563

     * Gives stdout one short drain interval per poll after the direct process exits.
     *
     * @return true when stdout reached EOF with no buffered rows, or false when polling must
     *     continue or engine cancellation won the race
     */
    private boolean awaitStdoutPumpAfterProcessExit() throws IOException {
        if (closeRequested) {
            return false;
        }
        if (stdoutCloseDeadlineNanos == 0L) {
            stdoutCloseDeadlineNanos =
                    System.nanoTime() + TimeUnit.SECONDS.toNanos(PROCESS_DESTROY_TIMEOUT_SECONDS);
        }
        if (!isAlive(stdoutPumpThread)) {
            return !closeRequested && stdoutLines.isEmpty();
        }
        if (!stdoutLines.isEmpty()) {
            if (System.nanoTime() >= stdoutCloseDeadlineNanos) {
                throw inheritedStdoutTimeout();
            }
            return false;
        }

        long remainingNanos = stdoutCloseDeadlineNanos - System.nanoTime();
        if (remainingNanos <= 0) {
            throw inheritedStdoutTimeout();
        }
        long waitMillis =
                Math.min(
                        PROCESS_EXIT_CHECK_TIMEOUT_MILLIS,
                        Math.max(1L, TimeUnit.NANOSECONDS.toMillis(remainingNanos)));
        try {
            stdoutPumpThread.join(waitMillis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException(
                    "Interrupted while draining Python source stdout after process exit", e);

View on GitHub (pinned to cf67b549a7)