pentaho/pentaho-kettle · error · KettleStepException

RegexEval.Exception.ErrorCaptureGroupFieldsMismatch

Error message

RegexEval.Exception.ErrorCaptureGroupFieldsMismatch

What it means

RegexEval.processRow throws KettleStepException when the regex's capture-group count does not match the number of configured capture-group output fields. The step cannot map match groups to target fields, so the row fails at match time with RegexEval.Exception.ErrorCaptureGroupFieldsMismatch.

Solutions

  1. Count the capture groups in your regex and make the fields list match exactly (one output field per group, in order)
  2. Remember group 0 is the whole match — groupCount() excludes it, so fields count must equal groupCount()
  3. Use a regex test tool (e.g. Spoon preview) to confirm group count before deploying
  4. If groups can vary per row, redesign so a fixed number of groups always matches

Example fix

// before
meta.setRegex("(\\d{4})-(\\d{2})");
meta.setFieldName(new String[] { "year", "month", "extra" });
// after
meta.setRegex("(\\d{4})-(\\d{2})");
// 2 capture groups -> exactly 2 output fields
meta.setFieldName(new String[] { "year", "month" });
meta.setFieldLength(...); // keep arrays consistent
Defensive patterns

Strategy: validation

Validate before calling

Pattern p = Pattern.compile(meta.getRegex());
if (meta.isAllowCaptureGroupsFlagSet() && p.matcher("").groupCount() != meta.getFieldName().length) {
  throw new IllegalArgumentException("Capture group count (" + p.matcher("").groupCount() + ") != output field count (" + meta.getFieldName().length + ")");
}

Try / catch

try { trans.execute(...); } catch (KettleException e) { if (e.getMessage().contains("CaptureGroupFieldsMismatch")) { logError("Align regex capture groups with the configured output fields"); } throw e; }

Prevention

When it happens

Trigger: At runtime, after a successful match, m.groupCount() differs from data.positions.length (the number of fields defined in the step) while 'Allow capture groups' is enabled — e.g. the regex was edited to add/remove a (…) group without updating the fields list.

Common situations: Editing the regular expression to add a new capture group but forgetting to add the corresponding output field; removing a group after fields were configured; count mismatch triggered only for rows where a different regex alternative matches with fewer groups.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/regexeval/RegexEval.java:160

      String fieldValue;
      boolean isMatch;

      if ( getInputRowMeta().isNull( row, data.indexOfFieldToEvaluate ) ) {
        fieldValue = "";
        isMatch = false;
      } else {
        fieldValue = getInputRowMeta().getString( row, data.indexOfFieldToEvaluate );

        // Start search engine
        Matcher m = data.pattern.matcher( fieldValue );
        isMatch = m.matches();

        if ( meta.isAllowCaptureGroupsFlagSet() && data.positions.length != m.groupCount() ) {
          // Runtime exception case. The number of capture groups in the
          // regex doesn't match the number of fields.
          logError( BaseMessages.getString( PKG, "RegexEval.Log.ErrorCaptureGroupFieldsMismatch", String
            .valueOf( m.groupCount() ), String.valueOf( data.positions.length ) ) );
          throw new KettleStepException( BaseMessages.getString(
            PKG, "RegexEval.Exception.ErrorCaptureGroupFieldsMismatch", String.valueOf( m.groupCount() ), String
              .valueOf( data.positions.length ) ) );
        }

        for ( int i = 0; i < data.positions.length; i++ ) {
          int index = data.positions[i];
          String value;
          if ( isMatch ) {
            value = m.group( i + 1 );
          } else {
            value = null;
          }

          // this part (or possibly the whole) of the regex didn't match
          // preserve the incoming data, but allow for "trim type", etc.
          if ( value == null ) {
            try {
              value = data.outputRowMeta.getString( outputRow, index );

View on GitHub (pinned to f3058517a1)