{"record":{"id":"01b0293e202366d9","repo":"pentaho/pentaho-kettle","slug":"merge-operation-op-is-not-defined","errorCode":null,"errorMessage":"Merge operation '${op}' is not defined.","messagePattern":"Merge operation '(.+?)' is not defined\\.","errorType":"exception","errorClass":"pentaho.lang.OperationInvalidError","httpStatus":null,"severity":"error","filePath":"plugins/core-ui/src/main/resources/app/pentaho/util/spec.js","lineNumber":102,"sourceCode":"      //   {$op: \"merge\", value: {}}\n      if((op = sourceValue.$op)) {\n        // Always deref source value, whether or not `op` is merge.\n        sourceValue = sourceValue.value;\n\n        // Merge operation only applies between two plain objects and\n        // add operation only applies between two arrays.\n        // Otherwise behaves like _replace_.\n        if(op === \"merge\" && !__isPlainJSObject(sourceValue) || op === \"add\" && !Array.isArray(sourceValue)) {\n          op = \"replace\";\n        }\n      } else {\n        op = \"merge\";\n      }\n    }\n\n    var handler = O.getOwn(_mergeHandlers, op || \"replace\");\n    if(!handler)\n      throw new OperationInvalidError(\"Merge operation '\" + op + \"' is not defined.\");\n\n    handler(target, name, sourceValue);\n  }\n\n  /**\n   * Performs the merge operation when the target value is also a plain object,\n   * or replaces it, if not.\n   *\n   * @param {object} target - The target object.\n   * @param {string} name - The source property name.\n   * @param {object} sourceValue - The source property value.\n   *\n   * @private\n   */\n  function __mergeOperMerge(target, name, sourceValue) {\n    // Is `targetValue` also a plain object?\n    var targetValue = target[name];\n    if(__isPlainJSObject(targetValue))","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/core-ui/src/main/resources/app/pentaho/util/spec.js#L84-L120","documentation":"`__mergeOne` in pentaho/util/spec.js performs a named merge operation (replace, merge, etc.) on a target property. If the operation name (from the value's `__mergeOp` or the spec) is not a registered handler in `_mergeHandlers`, it throws OperationInvalidError. This guards against typos or unsupported custom ops.","triggerScenarios":"Merging a spec/source value whose merge operation name is misspelled (e.g. `__mergeOp: \"mrege\"`) or names an op that was never registered in `_mergeHandlers`.","commonSituations":"Typo in a `__mergeOp` annotation; custom merge handler removed or renamed in a version upgrade; passing an op string built dynamically at runtime.","solutions":["Correct the operation name to a registered handler (e.g. 'replace' or 'merge')","Register a custom handler in _mergeHandlers before calling merge with that op","Log available op names to verify the expected value"],"exampleFix":"// before\nvar spec = { width: { value: 100, __mergeOp: \"overwrite\" } };\n// after\nvar spec = { width: { value: 100, __mergeOp: \"replace\" } };","handlingStrategy":"validation","validationCode":"var KNOWN_OPS = Object.keys(require(\"pentaho/util/spec\")._mergeHandlers || {});\nif (op && !KNOWN_OPS.includes(op)) throw new Error(\"Unknown merge op: \" + op);","typeGuard":"function isKnownMergeOp(op) { return typeof op === \"string\" && [\"replace\",\"merge\"].includes(op); }","tryCatchPattern":"try { merge(target, source); } catch (e) { if (e instanceof OperationInvalidError) { console.error(\"Bad __mergeOp in\", source); } throw e; }","preventionTips":["Only use documented __mergeOp values (replace, merge)","After upgrading, verify custom merge handlers are still registered"],"tags":["javascript","merge","configuration"],"backgroundTag":"invalid-enum-value","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"}