pentaho/pentaho-kettle · critical · KettleException
sqlldr returned an error (exit code )
Error message
sqlldr returned an error (exit code )
What it means
Thrown by checkExitVal when sqlldr exits with a code other than EX_SUCC (0) or EX_WARN (2) and failOnError is enabled. The message includes the actual exit code (rendered as empty in this message variant because the code was concatenated at runtime). It means the bulk load failed outright — no useful load occurred.
Solutions
- Check the sqlldr .log file for the underlying ORA- error and fix the database-side cause (credentials, table, privileges)
- Verify sqlldr is installed and on PATH for the user running Pentaho (exit code 127/2 from the shell)
- Verify the OraBulkLoaderMeta connection settings (host, port, database/SID, user, password)
- Keep failOnError=true (default) so failures are surfaced; if exit code came from a transient issue, correct it and re-run
Example fix
// before throw new KettleException( "sqlldr returned an error (exit code " + exitVal + ")" ); // after // capture and expose the sqlldr log so the real ORA- error is visible throw new KettleException( "sqlldr returned an error (exit code " + exitVal + "), see " + meta.getLogFile() );
Defensive patterns
Strategy: try-catch
Validate before calling
// verify prerequisites before the step runs assert new java.io.File( sqlldrPath ).exists() || streamCommandOnPath( "sqlldr" ); assert transMeta.findDatabase( connName ) != null;
Try / catch
try {
step.execute( meta, true );
} catch ( KettleException e ) {
java.util.regex.Matcher m = java.util.regex.Pattern.compile( "exit code (\\d+)" ).matcher( e.getMessage() );
if ( m.find() ) {
int code = Integer.parseInt( m.group( 1 ) );
// 1=fatal, 3=ORACLE errors, 4=OS errors — branch on code
}
} Prevention
- Validate Oracle credentials and target table existence before loading
- Ensure sqlldr is installed and on PATH for the executing user
- Keep failOnError enabled; monitor the sqlldr log file location
When it happens
Trigger: sqlldr process exits with e.g. 1 (fatal error), 3 or 4 (ORA- errors, OS errors) while meta.isFailOnError() is true; called from execute() after waitFor() or from processRow() for the stream load method.
Common situations: Wrong Oracle credentials/SID in the connection; malformed control file; table does not exist or no INSERT privilege; sqlldr binary not on PATH (command exit codes like 127).
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- sqlldr returned warning
- Error retrieving sqlldr string
- Error while closing output
- Error while executing sqlldr ''
- Error while executing sqlldr
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/ca847438c5acd630.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/oracle-bulk-loader/impl/src/main/java/org/pentaho/di/trans/steps/orabulkloader/OraBulkLoader.java:461
sb.append( " DIRECT=TRUE" );
if ( getStepMeta().getCopies() > 1 || meta.isParallel() ) {
sb.append( " PARALLEL=TRUE" );
}
}
return sb.toString();
}
public void checkExitVal( int exitVal ) throws KettleException {
if ( exitVal == EX_SUCC ) {
return;
}
if ( meta.isFailOnWarning() && ( exitVal == EX_WARN ) ) {
throw new KettleException( "sqlldr returned warning" );
} else if ( meta.isFailOnError() && ( exitVal != EX_WARN ) ) {
throw new KettleException( "sqlldr returned an error (exit code " + exitVal + ")" );
}
}
public boolean execute( OraBulkLoaderMeta meta, boolean wait ) throws KettleException {
Runtime rt = Runtime.getRuntime();
try {
sqlldrProcess = rt.exec( createCommandLine( meta, true ) );
// any error message?
StreamLogger errorLogger = new StreamLogger( sqlldrProcess.getErrorStream(), "ERROR" );
// any output?
StreamLogger outputLogger = new StreamLogger( sqlldrProcess.getInputStream(), "OUTPUT" );
// kick them off
errorLogger.start();
outputLogger.start();
View on GitHub (pinned to f3058517a1)