{"record":{"id":"9702cbb1e953d6ac","repo":"pentaho/pentaho-kettle","slug":"synchronizeaftermerge-exception-fieldrequired-keystream-i","errorCode":null,"errorMessage":"SynchronizeAfterMerge.Exception.FieldRequired (keyStream[i])","messagePattern":"SynchronizeAfterMerge\\.Exception\\.FieldRequired \\(keyStream\\[i\\]\\)","errorType":"exception","errorClass":"KettleStepException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/steps/synchronizeaftermerge/SynchronizeAfterMerge.java","lineNumber":713,"sourceCode":"      data.updateValue = environmentSubstitute( meta.getOrderUpdate() );\n      data.deleteValue = environmentSubstitute( meta.getOrderDelete() );\n\n      data.insertRowMeta = new RowMeta();\n\n      // lookup the values!\n      if ( log.isDebug() ) {\n        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++) {","sourceCodeStart":695,"sourceCodeEnd":731,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/steps/synchronizeaftermerge/SynchronizeAfterMerge.java#L695-L731","documentation":"The Synchronize After Merge step could not find one of the configured key fields (keyStream[i]) in the incoming row stream, and the key condition for that key still requires a field value. processRow() resolves each key field name to a row index during initialization of the row lookup; a negative index means the transformation wiring no longer matches the step configuration. It throws KettleStepException to fail fast before any rows are synchronized.","triggerScenarios":"The key field name in the step's 'Key stream' grid does not exist in the input RowMeta: the upstream step was renamed/removed, a Rename field step changed the name, the field casing differs, or the field was deleted from a preceding Select values step.","commonSituations":"Renaming a field upstream after configuring this step; pointing the step at a different table/file whose schema lacks the key columns; copying a transformation between environments where upstream metadata differs; typos in the key field name.","solutions":["Open the step and re-select the key fields from the available input fields so the names match the actual upstream stream","Insert or fix a 'Select values' (rename) step so the upstream field name equals the configured key stream name","Check field-name case sensitivity; Kettle field lookups are case-sensitive so make casing match exactly","Re-run upstream steps' preview to confirm the field exists at the point this step runs"],"exampleFix":"// before (upstream renamed customer_id to custId)\nKey stream: customer_id  ->  indexOfValue returns -1 -> KettleStepException\n// after\nOption A: update step config Key stream to custId\nOption B: upstream Select values: Rename custId -> customer_id","handlingStrategy":"validation","validationCode":"// PDI JS / before running the step\nvar fields = transMeta.getPrevStepFields(stepMeta);\nfor (var i = 0; i < stepMeta.getStepMetaInterface().getKeyStream().length; i++) {\n  var ks = stepMeta.getStepMetaInterface().getKeyStream()[i];\n  var cond = stepMeta.getStepMetaInterface().getKeyCondition()[i];\n  if (fields.indexOfValue(ks) < 0 && !\"IS NULL\".equalsIgnoreCase(cond) && !\"IS NOT NULL\".equalsIgnoreCase(cond)) {\n    throw new Error(\"Key field missing from input: \" + ks);\n  }\n}","typeGuard":"function hasField(rowMeta, name) { return rowMeta != null && name != null && rowMeta.indexOfValue(name) >= 0; }","tryCatchPattern":"try { trans.execute(...); } catch (KettleException e) { if (e.getMessage().contains(\"FieldRequired\")) { log.error(\"Re-check key field mapping: \" + e.getMessage()); /* fix mapping */ } else throw e; }","preventionTips":["Always pick key fields from the dialog dropdown rather than typing names","Re-open and re-save the step after renaming any upstream field","Preview the immediately preceding step before running the transformation","Keep field names consistent across environments with a naming convention"],"tags":["kettle","field-not-found","step-configuration","etl"],"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"}