pentaho/pentaho-kettle · error · KettleFileException

GroupBy.Exception.UnableToCloseInputStream

GroupBy.Exception.UnableToCloseInputStream

Error message

GroupBy.Exception.UnableToCloseInputStream

What it means

GroupBy throws this KettleFileException from closeOutput when the FileOutputStream used to buffer group rows to a temporary file cannot be closed without an IOException. It signals the temp file write-side cleanup failed, typically due to an underlying disk or stream problem.

Solutions

  1. Check disk space on the temp filesystem used by data.tempFile
  2. Avoid running dispose() twice on the same step data; ensure single lifecycle per transformation copy
  3. Close streams in a finally block only once; set references to null after closing (code already does)
  4. Inspect the wrapped IOException cause for the root OS error
  5. If on network storage, switch java.io.tmpdir to local disk

Example fix

// before
} catch ( IOException e ) {
  throw new KettleFileException(
    BaseMessages.getString( PKG, "GroupBy.Exception.UnableToCloseInputStream", data.tempFile.getPath() ), e );
// after
} catch ( IOException e ) {
  if ( data.fosToTempFile != null ) { try { data.fosToTempFile.close(); } catch ( IOException ignore ) {} }
  throw new KettleFileException(
    BaseMessages.getString( PKG, "GroupBy.Exception.UnableToCloseInputStream", data.tempFile.getPath() ), e );
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight disk space on temp volume
if ( new File( System.getProperty( "java.io.tmpdir" ) ).getUsableSpace() < 256L * 1024 * 1024 ) {
  throw new IllegalStateException( "Insufficient temp disk space for GroupBy spool" );
}

Try / catch

try {
  transformation.execute( arguments );
} catch ( KettleException e ) {
  if ( e.getMessage().contains( "UnableToCloseInputStream" ) ) {
    log.error( "GroupBy temp-file stream close failed; check disk and file locks", e );
  } else { throw e; }
}

Prevention

When it happens

Trigger: processRow or dispose calls closeOutput(); data.fosToTmpFile.close() (or the wrapped buffered stream) throws IOException because the temp file handle is broken, the disk is full, or the stream was already closed.

Common situations: Disk full while flushing the last buffer; NFS/Windows file-lock issues on the temp file; double-dispose racing on the same stream; OS-level file descriptor exhaustion.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/groupby/GroupBy.java:861

      } else {
        return null; // Nothing left!
      }
    }
  }

  private void closeOutput() throws KettleFileException {
    try {
      if ( data.dosToTempFile != null ) {
        data.dosToTempFile.close();
        data.dosToTempFile = null;
      }
      if ( data.fosToTempFile != null ) {
        data.fosToTempFile.close();
        data.fosToTempFile = null;
      }
      data.firstRead = true;
    } catch ( IOException e ) {
      throw new KettleFileException(
          BaseMessages.getString( PKG, "GroupBy.Exception.UnableToCloseInputStream", data.tempFile.getPath() ), e );
    }
  }

  private void closeInput() throws KettleFileException {
    try {
      if ( data.fisToTmpFile != null ) {
        data.fisToTmpFile.close();
        data.fisToTmpFile = null;
      }
      if ( data.disToTmpFile != null ) {
        data.disToTmpFile.close();
        data.disToTmpFile = null;
      }
    } catch ( IOException e ) {
      throw new KettleFileException(
          BaseMessages.getString( PKG, "GroupBy.Exception.UnableToCloseInputStream", data.tempFile.getPath() ), e );
    }

View on GitHub (pinned to f3058517a1)