pentaho/pentaho-kettle · error · KettleException

DynamicSQLRow.Exception.SQLEmpty

Error message

DynamicSQLRow.Exception.SQLEmpty

What it means

DynamicSQLRow.processRow validates on the first row that the step's configured SQL template (meta.getSql()) is non-empty and throws this KettleException otherwise. Without a base SQL template the step has nothing to execute.

Solutions

  1. Open the step dialog and enter the SQL template (use ? placeholders as needed)
  2. Confirm the template is saved in the step XML (<sql> tag)
  3. Re-save the transformation after entering the SQL
  4. If SQL should come entirely from the field, still provide a minimal template consistent with the step's design

Example fix

// before
<sql></sql>
// after
<sql>SELECT id, name FROM customers WHERE region = ?</sql>
Defensive patterns

Strategy: validation

Validate before calling

if (meta.getSql() == null || meta.getSql().trim().isEmpty()) {
  throw new IllegalStateException("Dynamic SQL Row: SQL template is empty");
}

Try / catch

try {
  // processRow validation
} catch (KettleException e) {
  logError("Enter the SQL template in the Dynamic SQL Row step", e);
  stopAll(); setErrors(1);
  return false;
}

Prevention

When it happens

Trigger: Executing a Dynamic SQL Row step whose 'SQL' text box was left empty in the dialog, or whose saved metadata lost the sql attribute.

Common situations: Step added but never configured; XML/repository record with an empty <sql> tag; template accidentally cleared while editing the transformation.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/df14691d5908e68c. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/dynamicsqlrow/DynamicSQLRow.java:222

  }

  public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {
    meta = (DynamicSQLRowMeta) smi;
    data = (DynamicSQLRowData) sdi;

    Object[] r = getRow(); // Get row from input rowset & set row busy!
    if ( r == null ) { // no more input to be expected...
      setOutputDone();
      return false;
    }
    if ( first ) {
      if ( Utils.isEmpty( meta.getSQLFieldName() ) ) {
        throw new KettleException( BaseMessages.getString( PKG, "DynamicSQLRow.Exception.SQLFieldNameEmpty" ) );
      }

      if ( Utils.isEmpty( meta.getSql() ) ) {
        throw new KettleException( BaseMessages.getString( PKG, "DynamicSQLRow.Exception.SQLEmpty" ) );
      }

      // cache the position of the field
      if ( data.indexOfSQLField < 0 ) {
        data.indexOfSQLField = getInputRowMeta().indexOfValue( meta.getSQLFieldName() );
        if ( data.indexOfSQLField < 0 ) {
          // The field is unreachable !
          throw new KettleException( BaseMessages.getString( PKG, "DynamicSQLRow.Exception.FieldNotFound", meta
            .getSQLFieldName() ) );
        }
      }
    }
    try {
      lookupValues( getInputRowMeta(), r );

      if ( checkFeedback( getLinesRead() ) ) {
        if ( log.isDetailed() ) {
          logDetailed( BaseMessages.getString( PKG, "DynamicSQLRow.Log.LineNumber" ) + getLinesRead() );

View on GitHub (pinned to f3058517a1)