apache/seatunnel · error · IOException

Interrupted while draining python source process output

Error message

Interrupted while draining python source process output

What it means

waitForPumpDrain joins an output pump thread (stdout or stderr) for a bounded time after the Python process exits. If the join is interrupted, the reader restores the interrupt flag and throws this IOException, aborting the orderly drain of remaining child output.

Source

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

        return true;
    }

    /** Creates the explicit protocol failure used when a child keeps the stdout pipe open. */
    private static IOException inheritedStdoutTimeout() {
        return new IOException(
                "Timed out waiting for Python source stdout to close after the process exited; ensure child processes do not inherit stdout");
    }

    /** Gives a pump a short grace period to consume bytes already written by the direct child. */
    private void waitForPumpDrain(Thread thread) throws IOException {
        if (thread == null || !thread.isAlive()) {
            return;
        }
        try {
            thread.join(PROCESS_EXIT_CHECK_TIMEOUT_MILLIS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("Interrupted while draining python source process output", e);
        }
    }

    private void checkPumpFailures() {
        if (stdoutPumpFailure != null) {
            throw new IllegalStateException(
                    "Failed to consume python source stdout", stdoutPumpFailure);
        }
        if (stderrPumpFailure == null) {
            return;
        }
        throw new IllegalStateException(
                "Failed to consume python source stderr", stderrPumpFailure);
    }

    /** Registers one poll so close cannot return while rows or completion are still emitted. */
    private boolean beginPoll() {
        synchronized (lifecycleLock) {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Treat as expected during deliberate cancellation; rerun otherwise
  2. Ensure the Python script flushes and closes stdout/stderr promptly on exit
  3. Check for job-level failures causing cascading interrupts across tasks
Defensive patterns

Strategy: try-catch

Try / catch

try {
    reader.close();
} catch (IOException e) {
    if (e.getMessage().contains("Interrupted while draining python source process output")) {
        // teardown-time interrupt; verify it coincides with a deliberate cancel
    }
}

Prevention

When it happens

Trigger: Interruption (task cancel/failure, engine shutdown) while finishPumpsAfterProcessExit waits on a pump thread via waitForPumpDrain.

Common situations: Job cancelled just as the Python process completed; pipeline failure elsewhere interrupts this task during its finish phase; repeated job restarts in a tight loop.

Related errors


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