pentaho/pentaho-kettle · error · KettleException

Error while closing output

Error message

Error while closing output

What it means

processRow() streams incoming rows to sqlldr's stdin through the 'output' writer; if closing that stream raises an IOException the step throws 'Error while closing output' with the original as cause. This happens while finalizing the pipe to the loader process, so sqlldr may not have received all data.

Solutions

  1. Check the sqlldr log — the child process usually crashed first (broken pipe); fix the root ORA- error from that log
  2. Verify the sqlldr command/credentials so the process stays alive while data is streamed
  3. Re-run the transformation; transient I/O errors on the pipe sometimes disappear
  4. If it persists, inspect the cause stack trace for 'Broken pipe' to confirm the child died mid-stream
Defensive patterns

Strategy: try-catch

Try / catch

try {
  step.processRow( smi, sdi );
} catch ( KettleException e ) {
  if ( e.getCause() instanceof java.io.IOException
       && e.getMessage().equals( "Error while closing output" ) ) {
    // broken pipe: child sqlldr died early — read sqlldr log for root cause
  }
}

Prevention

When it happens

Trigger: output.close() throws IOException during processRow's close sequence for the non-preview path of the stream (conventional) load method.

Common situations: sqlldr process already died (broken pipe) so the stdin stream is no longer writable; disk/OS-level I/O problems; JVM-level stream state issues after the child terminated early.

Related errors


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

Appendix: source

Thrown at plugins/oracle-bulk-loader/impl/src/main/java/org/pentaho/di/trans/steps/orabulkloader/OraBulkLoader.java:512

  public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {
    meta = (OraBulkLoaderMeta) smi;
    data = (OraBulkLoaderData) 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 ( OraBulkLoaderMeta.METHOD_AUTO_END.equals( loadMethod ) ) {
            // if this is the first line, we do not need to execute loader
            // control file may not exists
            if ( !first ) {
              execute( meta, true );
              sqlldrProcess = null;
            }
          } else if ( OraBulkLoaderMeta.METHOD_AUTO_CONCURRENT.equals( meta.getLoadMethod() ) ) {
            try {
              if ( sqlldrProcess != null ) {
                int exitVal = sqlldrProcess.waitFor();
                sqlldrProcess = null;

View on GitHub (pinned to f3058517a1)