pentaho/pentaho-kettle · error · KettleStepException

Unable to find table name field [] in input row

Error message

Unable to find table name field [] in input row

What it means

TableOutput was configured to take the target table name from a field in the incoming row ('table name defined in a field'), but the configured table name field could not be located in the row's metadata. indexOfValue() returns -1 when no field with that name (after environment substitution) exists, and the step refuses to continue because it cannot determine which table to write to. This is a strict fail-fast check before any row is written.

Solutions

  1. Open the TableOutput step dialog and correct the 'Table name field' to exactly match a field in the input stream.
  2. Inspect the incoming row metadata (right-click the hop / View > Fields) and ensure the table name field exists upstream of this step.
  3. If an environment variable is used in the field name, verify it is set in the transformation/run configuration.
  4. Alternatively, switch to a static table name in the step settings if the target table is fixed.

Example fix

// before
meta.setTableNameField( "${TABLE_FIELD}" ); // env var unset -> field name ""
// after
meta.setTableNameField( "tablename" ); // matches an actual field in the input row
Defensive patterns

Strategy: validation

Validate before calling

// Before writing, verify the table name field exists
int idx = rowMeta.indexOfValue( tableNameFieldName );
if ( idx < 0 ) {
  throw new IllegalArgumentException(
    "Fix TableOutput config: field '" + tableNameFieldName + "' not in input row" );
}

Type guard

boolean hasField = rowMeta.searchValueMeta( tableNameFieldName ) != null;

Try / catch

try { step.processRow(); } catch ( KettleStepException e ) {
  if ( e.getMessage().startsWith( "Unable to find table name field" ) ) {
    // correct step metadata or upstream stream
  }
}

Prevention

When it happens

Trigger: The step metadata specifies a table name field (meta.getTableNameField()) whose name, after environmentSubstitute(), does not match any field in the input row's RowMeta. Occurs on the first row processed by writeToTable.

Common situations: Typo in the 'table name field' setting; renaming or deleting the field upstream (Select values, Calculator) before TableOutput; wrong stream connected; environment variable for the field name not set so it resolves to an empty string; case-sensitivity mismatch in field names.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/tableoutput/TableOutput.java:176

    String tableName = null;

    boolean sendToErrorRow = false;
    String errorMessage = null;
    boolean rowIsSafe = false;
    int[] updateCounts = null;
    List<Exception> exceptionsList = null;
    boolean batchProblem = false;
    Object generatedKey = null;

    if ( meta.isTableNameInField() ) {
      // Cache the position of the table name field
      if ( data.indexOfTableNameField < 0 ) {
        String realTablename = environmentSubstitute( meta.getTableNameField() );
        data.indexOfTableNameField = rowMeta.indexOfValue( realTablename );
        if ( data.indexOfTableNameField < 0 ) {
          String message = "Unable to find table name field [" + realTablename + "] in input row";
          logError( message );
          throw new KettleStepException( message );
        }
        if ( !meta.isTableNameInTable() && !meta.specifyFields() ) {
          data.insertRowMeta.removeValueMeta( data.indexOfTableNameField );
        }
      }
      tableName = rowMeta.getString( r, data.indexOfTableNameField );
      if ( !meta.isTableNameInTable() && !meta.specifyFields() ) {
        // If the name of the table should not be inserted itself, remove the table name
        // from the input row data as well. This forcibly creates a copy of r
        //
        insertRowData = RowDataUtil.removeItem( rowMeta.cloneRow( r ), data.indexOfTableNameField );
      } else {
        insertRowData = r;
      }
    } else if ( meta.isPartitioningEnabled()
      && ( meta.isPartitioningDaily() || meta.isPartitioningMonthly() )
      && ( meta.getPartitioningField() != null && meta.getPartitioningField().length() > 0 ) ) {
      // Initialize some stuff!

View on GitHub (pinned to f3058517a1)