pentaho/pentaho-kettle · error · KettleStepException
Unable to get queryfields for SQL:
Error message
Unable to get queryfields for SQL:
What it means
In TableInputMeta.getFields() (impact-analysis path), the library previews the step's SQL via db.getQueryFields(sNewSQL, param) to derive the output row fields. When the database engine/driver rejects the SQL (KettleDatabaseException), it is wrapped in KettleStepException with message 'Unable to get queryfields for SQL: ' plus the SQL text.
Solutions
- Validate the step's SQL directly (Preview / SQL editor) — the exception message contains the full failing SQL.
- Resolve Kettle variables before analysis or set default values for ${var} placeholders.
- Test the database connection used by the step.
- If the SQL uses parameters (?), ensure they are supported in this path or restructure the query so getQueryFields can infer columns.
- Check the wrapped KettleDatabaseException cause for the driver's specific error.
Example fix
// before: unresolved variable breaks query-field inference
meta.setSQL("SELECT * FROM ${TABLE_NAME}");
// after: ensure the variable is defined before analyseImpact runs
transMeta.setVariable("TABLE_NAME", "customers");
meta.setSQL("SELECT * FROM ${TABLE_NAME}"); Defensive patterns
Strategy: try-catch
Validate before calling
// Java: check connection and resolve variables before getFields/analyseImpact
if (!databaseMeta.testConnectionSuccess()) throw new IllegalStateException("DB connection fails");
String resolved = transMeta.environmentSubstitute(meta.getSQL());
if (resolved.contains("${")) throw new IllegalStateException("Unresolved variables in SQL: " + resolved); Try / catch
try {
meta.getFields(row, origin, info, target, databaseMeta, metaStore);
} catch (KettleStepException e) {
log.error("Query field inference failed for SQL: " + e.getMessage() + ", cause: " + KettleUtil.getMessage(e));
} Prevention
- Resolve all ${variables} or give them defaults before impact analysis.
- Verify SQL syntax in the step's SQL editor / Preview before analysis.
- Test the database connection used by the step.
- Avoid dialect-specific constructs when you need automatic field inference.
When it happens
Trigger: analyseImpact -> getFields executes the SQL through Database.getQueryFields and the query fails: SQL syntax error, invalid variables (SQL with ${...} not yet substituted), connection failure, or schema/table referenced by the SQL does not exist.
Common situations: SQL containing unresolved Kettle variables or ?-parameters that getQueryFields cannot bind; typo in table/column names; database unreachable during impact analysis; dialect-specific SQL the driver's preview cannot parse.
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
- DynamicSQLRowMeta.Exception.UnableToDetermineQueryFields
- e (no own message; error caching lookup rows)
- Trans.Exception.ErrorInDatabase
- Unable to load job entry copy from repository with…
- Unable to prepare combi-lookup statement
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/c5082b3a4c9c3b7c.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/tableinput/TableInputMeta.java:233
boolean param = false;
Database db = getDatabase();
super.databases = new Database[] { db }; // keep track of it for canceling purposes...
// First try without connecting to the database... (can be S L O W)
String sNewSQL = sql;
if ( isVariableReplacementActive() ) {
sNewSQL = db.environmentSubstitute( sql );
if ( space != null ) {
sNewSQL = space.environmentSubstitute( sNewSQL );
}
}
RowMetaInterface add = null;
try {
add = db.getQueryFields( sNewSQL, param );
} catch ( KettleDatabaseException dbe ) {
throw new KettleStepException( "Unable to get queryfields for SQL: " + Const.CR + sNewSQL, dbe );
}
if ( add != null ) {
attachOrigin( add, origin );
row.addRowMeta( add );
} else {
try {
db.connect();
RowMetaInterface paramRowMeta = null;
Object[] paramData = null;
StreamInterface infoStream = getStepIOMeta().getInfoStreams().get( 0 );
if ( !Utils.isEmpty( infoStream.getStepname() ) ) {
param = true;
if ( info.length > 0 && info[ 0 ] != null ) {
paramRowMeta = info[ 0 ];
paramData = RowDataUtil.allocateRowData( paramRowMeta.size() );View on GitHub (pinned to f3058517a1)