pentaho/pentaho-kettle · error · KettleException

TableExists.Exception.CouldnotFindField

Error message

TableExists.Exception.CouldnotFindField

What it means

TableExists.processRow throws this when the configured dynamic-table-name field cannot be found in the incoming row structure. The field name is set, but indexOfValue() on the input RowMeta returns -1, meaning no such column arrives at the step.

Solutions

  1. Ensure the upstream step actually emits a column matching the configured 'Tablename field' name exactly
  2. Open the step dialog and re-select the field from the updated input layout
  3. Preview the upstream step to confirm the field name and case
  4. Add or fix the upstream step (e.g. Calculator/Select values) that should produce the field

Example fix

// before: upstream dropped the field
// SQL: SELECT other_col FROM src
// after: emit the field the step expects
// SQL: SELECT tablename, other_col FROM src
Defensive patterns

Strategy: validation

Validate before calling

// verify the field exists in the incoming layout before running
TableExistsMeta meta = (TableExistsMeta) stepMeta.getStepMetaInterface();
RowMetaInterface prev = transMeta.getPrevStepFields(stepMeta);
if (prev.indexOfValue(meta.getDynamicTablenameField()) < 0) {
  throw new IllegalStateException("Field '" + meta.getDynamicTablenameField() + "' not produced by upstream steps");
}

Try / catch

try { trans.execute(null); }
catch (KettleException e) {
  if (e.getMessage().contains("CouldnotFindField")) {
    logError("Re-map the tablename field: upstream layout changed");
  }
}

Prevention

When it happens

Trigger: Running the transformation where getInputRowMeta().indexOfValue(meta.getDynamicTablenameField()) returns -1 — upstream step no longer emits the field, field was renamed, or the configured name differs by case/whitespace.

Common situations: Renaming or removing an upstream Select values/Text file output field; changing an upstream SQL to drop the column; mismatch between 'Tablename field' and the actual column name; transformations edited after upstream layout changes.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/tableexists/TableExists.java:81

        first = false;
        data.outputRowMeta = getInputRowMeta().clone();
        meta.getFields( getTransMeta().getBowl(), data.outputRowMeta, getStepname(), null, null, this, repository,
          metaStore );

        // Check is tablename field is provided
        if ( Utils.isEmpty( meta.getDynamicTablenameField() ) ) {
          logError( BaseMessages.getString( PKG, "TableExists.Error.TablenameFieldMissing" ) );
          throw new KettleException( BaseMessages.getString( PKG, "TableExists.Error.TablenameFieldMissing" ) );
        }

        // cache the position of the field
        if ( data.indexOfTablename < 0 ) {
          data.indexOfTablename = getInputRowMeta().indexOfValue( meta.getDynamicTablenameField() );
          if ( data.indexOfTablename < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "TableExists.Exception.CouldnotFindField" )
              + "[" + meta.getDynamicTablenameField() + "]" );
            throw new KettleException( BaseMessages.getString(
              PKG, "TableExists.Exception.CouldnotFindField", meta.getDynamicTablenameField() ) );
          }
        }
      } // End If first

      // get tablename
      String tablename = getInputRowMeta().getString( r, data.indexOfTablename );

      // Check if table exists on the specified connection
      tablexists = data.db.checkTableExists( data.realSchemaname, tablename );

      Object[] outputRowData = RowDataUtil.addValueData( r, getInputRowMeta().size(), tablexists );

      // add new values to the row.
      putRow( data.outputRowMeta, outputRowData ); // copy row to output rowset(s);

      if ( log.isRowLevel() ) {
        logRowlevel( BaseMessages.getString( PKG, "TableExists.LineNumber", getLinesRead()

View on GitHub (pinned to f3058517a1)