{"record":{"id":"9b6b108e1d55f7ca","repo":"pentaho/pentaho-kettle","slug":"synchronizeaftermerge-exception-fieldrequired-keystream2-i","errorCode":null,"errorMessage":"SynchronizeAfterMerge.Exception.FieldRequired (keyStream2[i])","messagePattern":"SynchronizeAfterMerge\\.Exception\\.FieldRequired \\(keyStream2\\[i\\]\\)","errorType":"exception","errorClass":"KettleStepException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/synchronizeaftermerge/SynchronizeAfterMerge.java","lineNumber":720,"sourceCode":"        logDebug( BaseMessages.getString( PKG, \"SynchronizeAfterMerge.Log.CheckingRow\" ) + Arrays.toString( nextRow ) );\n      }\n\n      data.keynrs = new int[meta.getKeyStream().length];\n      data.keynrs2 = new int[meta.getKeyStream().length];\n      for (int i = 0; i < meta.getKeyStream().length; i++) {\n        data.keynrs[i] = data.inputRowMeta.indexOfValue( meta.getKeyStream()[i] );\n        if ( data.keynrs[i] < 0 && // couldn't find field!\n          !\"IS NULL\".equalsIgnoreCase( meta.getKeyCondition()[i] ) && // No field needed!\n          !\"IS NOT NULL\".equalsIgnoreCase( meta.getKeyCondition()[i] ) // No field needed!\n        ) {\n          throw new KettleStepException( BaseMessages.getString( PKG, \"SynchronizeAfterMerge.Exception.FieldRequired\",\n            meta.getKeyStream()[i] ) );\n        }\n        data.keynrs2[i] = data.inputRowMeta.indexOfValue( meta.getKeyStream2()[i] );\n        if ( data.keynrs2[i] < 0 && // couldn't find field!\n          \"BETWEEN\".equalsIgnoreCase( meta.getKeyCondition()[i] ) // 2 fields needed!\n        ) {\n          throw new KettleStepException( BaseMessages.getString( PKG, \"SynchronizeAfterMerge.Exception.FieldRequired\",\n            meta.getKeyStream2()[i] ) );\n        }\n\n        if ( log.isDebug() ) {\n          logDebug( BaseMessages.getString( PKG, \"SynchronizeAfterMerge.Log.FieldHasDataNumbers\", meta\n            .getKeyStream()[i] ) + data.keynrs[i] );\n        }\n      }\n\n      // Insert the update fields: just names. Type doesn't matter!\n      for (int i = 0; i < meta.getUpdateLookup().length; i++) {\n        ValueMetaInterface insValue = data.insertRowMeta.searchValueMeta( meta.getUpdateLookup()[i] );\n        if ( insValue == null ) { // Don't add twice!\n          // we already checked that this value exists so it's probably safe to ignore lookup failure...\n          ValueMetaInterface insertValue = data.inputRowMeta.searchValueMeta( meta.getUpdateStream()[i] ).clone();\n          insertValue.setName( meta.getUpdateLookup()[i] );\n          data.insertRowMeta.addValueMeta( insertValue );\n        } else {","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/synchronizeaftermerge/SynchronizeAfterMerge.java#L702-L738","documentation":"Same family as the keyStream lookup failure, but for the second key field (keyStream2[i]). The lookup for keyStream2 only matters when the key condition is BETWEEN, which requires two fields; if keyStream2[i] cannot be found in the input rows and the condition is BETWEEN, processRow() throws KettleStepException.","triggerScenarios":"A key entry with condition BETWEEN has its second field (Key stream 2) set to a name absent from the input row layout — typically because the field was renamed, removed, or never existed upstream.","commonSituations":"Configuring BETWEEN comparisons on date/numeric ranges where one bound field was renamed upstream; pasting a step config from another transformation with a different stream schema.","solutions":["Open the step and re-select Key stream 2 fields for entries using the BETWEEN condition","If BETWEEN is no longer needed, change the key condition (e.g., to '=' ) so no second field is required","Add a Select values rename step upstream to restore the expected field name","Preview the upstream step output and verify the second field name exists and matches exactly"],"exampleFix":"// before\ncondition: BETWEEN, keyStream2: end_date (renamed upstream to date_end) -> throw\n// after\ncondition: BETWEEN, keyStream2: date_end\n// or change condition to '=' if the second bound is unnecessary","handlingStrategy":"validation","validationCode":"var m = stepMeta.getStepMetaInterface();\nfor (var i = 0; i < m.getKeyStream2().length; i++) {\n  if (\"BETWEEN\".equalsIgnoreCase(m.getKeyCondition()[i]) && transMeta.getPrevStepFields(stepMeta).indexOfValue(m.getKeyStream2()[i]) < 0) {\n    throw new Error(\"Key stream 2 field missing: \" + m.getKeyStream2()[i]);\n  }\n}","typeGuard":"function betweenKeysValid(meta, rowMeta) { return meta.getKeyStream2().every(function(k, i) { return !\"BETWEEN\".equalsIgnoreCase(meta.getKeyCondition()[i]) || rowMeta.indexOfValue(k) >= 0; }); }","tryCatchPattern":"try { trans.execute(...); } catch (KettleException e) { if (e.getMessage().contains(\"keyStream2\") || e.getMessage().contains(\"FieldRequired\")) { log.error(\"Fix BETWEEN key field 2: \" + e.getMessage()); } else throw e; }","preventionTips":["Only use BETWEEN conditions when both bound fields exist in the stream","Change condition to '=' when a second bound field is unnecessary","Preview upstream fields after any schema change","Avoid hand-editing step XML; use the dialog"],"tags":["kettle","field-not-found","between-condition","step-configuration"],"backgroundTag":"resource-not-found","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}