pentaho/pentaho-kettle · error · KettleStepException
DatabaseJoinMeta.Exception.UnableToDetermineQueryFields +…
Error message
DatabaseJoinMeta.Exception.UnableToDetermineQueryFields + Const.CR + sql
What it means
DatabaseJoinMeta.getFields() asks the database for the result layout of the injected SQL (db.getQueryFields, with environment-substituted variables) to append the returned columns to the row; a KettleDatabaseException is rethrown as KettleStepException 'UnableToDetermineQueryFields' plus the SQL. The step needs the query's field metadata to build the output row and cannot proceed without it.
Solutions
- Copy the SQL appended in the message (after Const.CR) and run it directly against the database to see the real error.
- Fix the SQL syntax or referenced tables/columns in the Database Join dialog.
- Ensure all ${VARIABLES} in the SQL are defined (KETTLE variables / environment) before execution.
- Verify the step's database connection settings and that the DB is reachable.
Example fix
// before: SQL referencing a renamed table String sql = "SELECT * FROM cust_old WHERE id = ?"; // after String sql = "SELECT * FROM customer WHERE id = ?";
Defensive patterns
Strategy: validation
Validate before calling
String resolved = transMeta.environmentSubstitute(meta.getSql());
if (resolved.contains("${")) throw new IllegalArgumentException("Unresolved variables in SQL: " + resolved);
try (PreparedStatement ps = connection.prepareStatement(resolved)) { /* metadata prepared OK */ } Try / catch
try { transMeta.initializeVariablesFrom(null); }
catch (KettleStepException e) {
if (e.getMessage().contains("UnableToDetermineQueryFields")) {
String sql = e.getMessage().substring(e.getMessage().indexOf(Const.CR) + 1);
log.error("Fix this SQL manually: {}", sql);
}
} Prevention
- Test the SQL in a DB client before putting it into the step
- Define all Kettle variables used in the SQL at run time
- Re-test metadata retrieval after schema migrations
When it happens
Trigger: Transformation initialization or analyseImpact when the SQL is invalid (syntax error, unknown table/columns), the substituted variables produce broken SQL, or the database connection fails while preparing the statement for metadata retrieval.
Common situations: Variable placeholders not set in the run environment; SQL tuned for a different DB dialect; missing table after a schema migration; connection points to the wrong database.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- DynamicSQLRow.Exception.IncorrectNrTemplateFields
- SQLFileOutputMeta.Exception.ErrorGettingFields
- SQLFileOutputMeta.Exception.TableNotFound
- BaseStreamStepMeta.CheckResult.ResultStepMissing
- CheckSum.Error.UnknownEvaluationMethod
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/079198cb7fe50c0c.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/databasejoin/DatabaseJoinMeta.java:296
return;
}
Database db = new Database( loggingObject, databaseMeta );
databases = new Database[] { db }; // Keep track of this one for cancelQuery
// Which fields are parameters?
// info[0] comes from the database connection.
//
RowMetaInterface param = getParameterRow( row );
// First try without connecting to the database... (can be S L O W)
// See if it's in the cache...
//
RowMetaInterface add = null;
try {
add = db.getQueryFields( space.environmentSubstitute( sql ), true, param, new Object[param.size()] );
} catch ( KettleDatabaseException dbe ) {
throw new KettleStepException( BaseMessages.getString(
PKG, "DatabaseJoinMeta.Exception.UnableToDetermineQueryFields" )
+ Const.CR + sql, dbe );
}
if ( add != null ) { // Cache hit, just return it this...
for ( int i = 0; i < add.size(); i++ ) {
ValueMetaInterface v = add.getValueMeta( i );
v.setOrigin( name );
}
row.addRowMeta( add );
} else {
// No cache hit, connect to the database, do it the hard way...
//
try {
db.connect();
add = db.getQueryFields( space.environmentSubstitute( sql ), true, param, new Object[param.size()] );
for ( int i = 0; i < add.size(); i++ ) {
ValueMetaInterface v = add.getValueMeta( i );View on GitHub (pinned to f3058517a1)