{"record":{"id":"f35c3e3364ae51fb","repo":"pentaho/pentaho-kettle","slug":"error-calling-extension-point-at-end-of-transformation","errorCode":null,"errorMessage":"Error calling extension point at end of transformation","messagePattern":"Error calling extension point at end of transformation","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/Trans.java","lineNumber":1501,"sourceCode":"\n    transFinishedBlockingQueue = new ArrayBlockingQueue<>( TRANS_FINISHED_BLOCKING_QUEUE_SIZE );\n\n    TransListener transListener = new TransAdapter() {\n      @Override\n      public void transFinished( Trans trans ) {\n\n        try {\n          shutdownHeartbeat( trans != null ? trans.heartbeat : null );\n          if ( trans != null && transMeta.getParent() == null && trans.parentJob == null && trans.parentTrans == null ) {\n            if ( log.isDetailed() && transMeta.getMetaFileCache() != null ) {\n              transMeta.getMetaFileCache().logCacheSummary( log );\n            }\n            transMeta.setMetaFileCache( null );\n          }\n\n          ExtensionPointHandler.callExtensionPoint( log, KettleExtensionPoint.TransformationFinish.id, trans );\n        } catch ( KettleException e ) {\n          throw new RuntimeException( \"Error calling extension point at end of transformation\", e );\n        }\n\n        // First of all, stop the performance snapshot timer if there is is\n        // one...\n        //\n        if ( transMeta.isCapturingStepPerformanceSnapShots() && stepPerformanceSnapShotTimer != null ) {\n          stepPerformanceSnapShotTimer.cancel();\n        }\n\n        transMeta.disposeEmbeddedMetastoreProvider();\n\n        setFinished( true );\n        setRunning( false ); // no longer running\n\n        log.snap( Metrics.METRIC_TRANSFORMATION_EXECUTION_STOP );\n\n        // If the user ran with metrics gathering enabled and a metrics logging table is configured, add another\n        // listener...","sourceCodeStart":1483,"sourceCodeEnd":1519,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/Trans.java#L1483-L1519","documentation":"Pentaho Kettle (PDI) fires the TransformationFinish extension point when a transformation completes. If any registered extension point plugin throws a KettleException during that callback, Trans wraps it in a RuntimeException with this message. The transformation itself has finished; the failure is in a plugin hooking the end-of-transformation lifecycle.","triggerScenarios":"A plugin registered under the KettleExtensionPoint.TransformationFinish extension point throws a KettleException inside its callExtensionPoint() implementation while Trans.executeTransformation()/run() is finishing.","commonSituations":"A custom or third-party plugin (e.g. a monitoring/audit listener) tries to write to a database, file, or remote endpoint at transformation end and fails due to connectivity, permissions, or a bug in the plugin; an outdated plugin incompatible with the current Kettle version.","solutions":["Check the cause stack trace to identify which extension point plugin threw","Fix or update the failing plugin (check its DB/file/network access at transformation end)","Temporarily remove the plugin jar from the plugins directory to confirm it is the culprit","Wrap the plugin's callExtensionPoint body with its own error handling/logging so it does not propagate"],"exampleFix":"// before: plugin propagates errors\npublic void callExtensionPoint(LogChannelInterface log, Object object) throws KettleException {\n  writeAudit((Trans) object);\n}\n// after: plugin handles its own failures\npublic void callExtensionPoint(LogChannelInterface log, Object object) throws KettleException {\n  try { writeAudit((Trans) object); }\n  catch (Exception e) { log.logError(\"Audit write failed\", e); }\n}","handlingStrategy":"try-catch","validationCode":"List<String> plugins = KettleExtensionPoint.TransformationFinish.getExtensions();\nif (plugins != null && !plugins.isEmpty()) System.out.println(\"Finish plugins registered: \" + plugins);","typeGuard":"boolean isExtensionPointFailure(RuntimeException e) {\n  return \"Error calling extension point at end of transformation\".equals(e.getMessage()) && e.getCause() instanceof KettleException;\n}","tryCatchPattern":"try {\n  trans.execute(args); trans.waitUntilFinished();\n} catch (RuntimeException e) {\n  if (e.getCause() instanceof KettleException) {\n    log.warn(\"Transformation finished but an extension point plugin failed\", e.getCause());\n  } else throw e;\n}","preventionTips":["Test extension point plugins in isolation against your Kettle version","Keep plugin jars updated and compatible with the PDI release","Audit plugins/ directory for unused or broken plugins","Have plugins log and swallow their own non-fatal errors"],"tags":["kettle","extension-point","plugin","lifecycle"],"backgroundTag":"plugin-callback-failed","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"}