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
- Check the psql log file / process stderr for the real psql-side failure that killed the pipe.
- Verify database connectivity and authentication (pg_hba.conf, .pgpass) from the Kettle host.
- Validate the control file: target table, column list, and format must match the incoming row structure.
- 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
- Always capture and check the psql process's exit code and stderr, not just the stream close
- Pre-validate auth (pg_hba.conf/.pgpass) and the control file's target table before loading
- Watch psql logs for early exits during long loads (OOM, network drops)
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
- Error while executing psql \'
- <toString()> : Unable to read value metadata from input…
- Already closed
- Already closed
- An error occurred writing data to the MonetDB API (MAPI)…
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)