pentaho/pentaho-kettle · error · KettleException

Error while closing output

Error message

Error while closing output

What it means

processRow() writes rows into the psql process's stdin via the `output` stream. When the step finishes (and not in preview mode) it closes that stream; an IOException there is wrapped in this KettleException. A close failure almost always means the psql process has already died and closed the pipe, so the real load failure surfaced as a broken pipe on the Kettle side.

Solutions

  1. Check the psql log file / process stderr for the real psql-side failure that killed the pipe.
  2. Verify database connectivity and authentication (pg_hba.conf, .pgpass) from the Kettle host.
  3. Validate the control file: target table, column list, and format must match the incoming row structure.
  4. Inspect ex.getCause() for 'Broken pipe' to confirm the child process died before close; add try-with-resources to guarantee cleanup.

Example fix

// before: stream left to manual close, error surfaces at close()
output = ...; // write rows...
output.close();

// after: use try-with-resources and validate psql availability first
try (OutputStream out = output) {
  // write rows
}
// and check the child process exit code/stderr for the root cause
Defensive patterns

Strategy: try-catch

Validate before calling

// before writing, confirm the psql process is still alive
if (process != null && !process.isAlive()) {
  throw new IllegalStateException(
    "psql exited early with code " + process.exitValue()
    + " - check psql stderr/log before writing rows");
}

Try / catch

try {
  execute(meta, wait);
} catch (KettleException e) {
  if (e.getMessage().contains("Error while closing output")) {
    logError("psql died before stdin was closed - root cause is on the psql side", e.getCause());
    // inspect psql log file / stderr for auth, control-file, or table errors
  } else throw e;
}

Prevention

When it happens

Trigger: processRow() reaches the finalization block with output != null and output.close() throws IOException - typically because psql exited early (bad credentials, control file error, syntax error) and the pipe is broken; the stream may also already be closed by the child process terminating.

Common situations: psql fails at startup due to pg_hba.conf rejecting the connection; control file references a nonexistent table so psql aborts mid-load; psql killed by OOM; network drop between Kettle host and Greenplum kills the session while rows are still being written.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/6ce33e0cf2adbc23. Report an issue: GitHub.

Appendix: source

Thrown at plugins/gp-bulk-loader/core/src/main/java/org/pentaho/di/trans/steps/gpbulkloader/GPBulkLoader.java:447

  public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {
    meta = (GPBulkLoaderMeta) smi;
    data = (GPBulkLoaderData) sdi;

    try {
      Object[] r = getRow(); // Get row from input rowset & set row busy!
      if ( r == null ) {
        // no more input to be expected...

        setOutputDone();

        if ( !preview ) {
          if ( output != null ) {
            // Close the output
            try {
              output.close();
            } catch ( IOException e ) {
              throw new KettleException( "Error while closing output", e );
            }

            output = null;
          }

          String loadMethod = meta.getLoadMethod();
          if ( GPBulkLoaderMeta.METHOD_AUTO_END.equals( loadMethod ) ) {
            execute( meta, true );
          }
          // else if ( GPBulkLoaderMeta.METHOD_AUTO_CONCURRENT.equals(meta.getLoadMethod()) )
          // {
          // try
          // {
          // if ( psqlProcess != null )
          // {
          // int exitVal = psqlProcess.waitFor();
          // logBasic(BaseMessages.getString(PKG, "GPBulkLoader.Log.ExitValueSqlldr", "" + exitVal));
          // }

View on GitHub (pinned to f3058517a1)