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
- Count the capture groups in your regex and make the fields list match exactly (one output field per group, in order)
- Remember group 0 is the whole match — groupCount() excludes it, so fields count must equal groupCount()
- Use a regex test tool (e.g. Spoon preview) to confirm group count before deploying
- 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
- Recount capture groups every time the regex changes
- Remember groupCount() excludes group 0 (whole match)
- Test regexes in Spoon preview before production
- Use named groups and document the expected group count near the step
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
- RegexEval.Exception.ErrorMatcherMissing
- RegexEval.Exception.ErrorResultFieldMissing
- At least one slave server is required to be present in…
- ChangeFileEncoding.Error.TargetFileIsEmpty
- DynamicSQLRow.Exception.SQLFieldNameEmpty
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)