pentaho/pentaho-kettle · error · KettleException
GPG.IOException
Error message
GPG.IOException
What it means
Thrown by GPG.execGnuPG when spawning the gpg command-line process fails with a java.io.IOException. The gpg binary is invoked via Runtime.exec or ProcessBuilder (/bin/sh -c on non-Windows); if process creation fails, this wrapped KettleException is raised.
Solutions
- Confirm the gpg executable still exists and is executable at runtime (chmod +x, correct path).
- Check the wrapped IOException (getCause()) for errno details (ENOENT, EACCES, EMFILE).
- Raise the file-descriptor limit (ulimit -n) if EMFILE/too many open files is reported.
- On Windows ensure the path is quoted correctly; on non-Windows ensure /bin/sh exists in the runtime environment/container.
Example fix
// before String command = gpgexe + " --decrypt " + filename; // unquoted spaces break exec // after String command = "\"" + gpgexe + "\" --decrypt \"" + filename + "\""; // quoted paths p = Runtime.getRuntime().exec( command );
Defensive patterns
Strategy: try-catch
Validate before calling
java.io.File gpg = new java.io.File( gpgexe ); if ( !gpg.canExecute() ) throw new IllegalStateException( "gpg not executable: " + gpgexe ); // check fd headroom if ( new java.io.File( "/proc/self/fd" ).list().length > 20000 ) log.warn( "High fd usage; exec may fail" );
Type guard
boolean canExecGpg( String p ) { return p != null && new java.io.File( p ).canExecute(); } Try / catch
try {
gpg.execGnuPG( args );
} catch ( KettleException e ) {
if ( e.getCause() instanceof java.io.IOException ) {
java.io.IOException io = (java.io.IOException) e.getCause();
logError( "Failed to launch gpg: " + io.getMessage() + " — check path, permissions, and ulimit" );
}
} Prevention
- Verify the gpg binary exists and is executable immediately before execution.
- Raise ulimit -n on hosts running many GPG operations.
- Ensure /bin/sh exists in containers used on non-Windows platforms.
- Quote executable and file paths to survive spaces.
- Check the wrapped IOException errno to target the fix.
When it happens
Trigger: Runtime.getRuntime().exec(command) or processBuilder.start() throws IOException — the executable path is invalid at exec time, working directory inaccessible, too many open files, or (on some JVMs) Command file creation fails.
Common situations: GPG binary deleted/moved between validation and execution; insufficient OS file descriptors (ulimit) under load; execute permission removed from the binary; container images without /bin/sh when ProcessBuilder path is used; ENOMEM/process limits hit.
Related errors
- Error while executing psql \'
- GPG.ErrorCreatingTempFile
- GPG.ErrorWritingTempFile
- GPG.ExceptionWrite
- IO exception while running the process
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/7715ada8a7a3a55e.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/job/entries/pgpencryptfiles/GPG.java:184
*/
private String execGnuPG( String commandArgs, String inputStr, boolean fileMode ) throws KettleException {
Process p;
String command = getGpgExeFile() + " " + ( fileMode ? "" : gnuPGCommand + " " ) + commandArgs;
if ( log.isDebug() ) {
log.logDebug( BaseMessages.getString( PKG, "GPG.RunningCommand", command ) );
}
String retval;
try {
if ( Const.isWindows() ) {
p = Runtime.getRuntime().exec( command );
} else {
ProcessBuilder processBuilder = new ProcessBuilder( "/bin/sh", "-c", command );
p = processBuilder.start();
}
} catch ( IOException io ) {
throw new KettleException( BaseMessages.getString( PKG, "GPG.IOException" ), io );
}
ProcessStreamReader psr_stdout = new ProcessStreamReader( p.getInputStream() );
ProcessStreamReader psr_stderr = new ProcessStreamReader( p.getErrorStream() );
psr_stdout.start();
psr_stderr.start();
if ( inputStr != null ) {
BufferedWriter out = new BufferedWriter( new OutputStreamWriter( p.getOutputStream() ) );
try {
out.write( inputStr );
} catch ( IOException io ) {
throw new KettleException( BaseMessages.getString( PKG, "GPG.ExceptionWrite" ), io );
} finally {
if ( out != null ) {
try {
out.close();
} catch ( Exception e ) {
// IgnoreView on GitHub (pinned to f3058517a1)