{"record":{"id":"6ce33e0cf2adbc23","repo":"pentaho/pentaho-kettle","slug":"error-while-closing-output","errorCode":null,"errorMessage":"Error while closing output","messagePattern":"Error while closing output","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/gp-bulk-loader/core/src/main/java/org/pentaho/di/trans/steps/gpbulkloader/GPBulkLoader.java","lineNumber":447,"sourceCode":"\n  public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {\n    meta = (GPBulkLoaderMeta) smi;\n    data = (GPBulkLoaderData) sdi;\n\n    try {\n      Object[] r = getRow(); // Get row from input rowset & set row busy!\n      if ( r == null ) {\n        // no more input to be expected...\n\n        setOutputDone();\n\n        if ( !preview ) {\n          if ( output != null ) {\n            // Close the output\n            try {\n              output.close();\n            } catch ( IOException e ) {\n              throw new KettleException( \"Error while closing output\", e );\n            }\n\n            output = null;\n          }\n\n          String loadMethod = meta.getLoadMethod();\n          if ( GPBulkLoaderMeta.METHOD_AUTO_END.equals( loadMethod ) ) {\n            execute( meta, true );\n          }\n          // else if ( GPBulkLoaderMeta.METHOD_AUTO_CONCURRENT.equals(meta.getLoadMethod()) )\n          // {\n          // try\n          // {\n          // if ( psqlProcess != null )\n          // {\n          // int exitVal = psqlProcess.waitFor();\n          // logBasic(BaseMessages.getString(PKG, \"GPBulkLoader.Log.ExitValueSqlldr\", \"\" + exitVal));\n          // }","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/gp-bulk-loader/core/src/main/java/org/pentaho/di/trans/steps/gpbulkloader/GPBulkLoader.java#L429-L465","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: stream left to manual close, error surfaces at close()\noutput = ...; // write rows...\noutput.close();\n\n// after: use try-with-resources and validate psql availability first\ntry (OutputStream out = output) {\n  // write rows\n}\n// and check the child process exit code/stderr for the root cause","handlingStrategy":"try-catch","validationCode":"// before writing, confirm the psql process is still alive\nif (process != null && !process.isAlive()) {\n  throw new IllegalStateException(\n    \"psql exited early with code \" + process.exitValue()\n    + \" - check psql stderr/log before writing rows\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  execute(meta, wait);\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"Error while closing output\")) {\n    logError(\"psql died before stdin was closed - root cause is on the psql side\", e.getCause());\n    // inspect psql log file / stderr for auth, control-file, or table errors\n  } else throw e;\n}","preventionTips":["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)"],"tags":["io","broken-pipe","psql","stream","kettle"],"backgroundTag":"broken-pipe","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}