pentaho/pentaho-kettle · error · RuntimeException
Error calling extension point at end of transformation
Error message
Error calling extension point at end of transformation
What it means
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.
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
Example fix
// before: plugin propagates errors
public void callExtensionPoint(LogChannelInterface log, Object object) throws KettleException {
writeAudit((Trans) object);
}
// after: plugin handles its own failures
public void callExtensionPoint(LogChannelInterface log, Object object) throws KettleException {
try { writeAudit((Trans) object); }
catch (Exception e) { log.logError("Audit write failed", e); }
} Defensive patterns
Strategy: try-catch
Validate before calling
List<String> plugins = KettleExtensionPoint.TransformationFinish.getExtensions();
if (plugins != null && !plugins.isEmpty()) System.out.println("Finish plugins registered: " + plugins); Type guard
boolean isExtensionPointFailure(RuntimeException e) {
return "Error calling extension point at end of transformation".equals(e.getMessage()) && e.getCause() instanceof KettleException;
} Try / catch
try {
trans.execute(args); trans.waitUntilFinished();
} catch (RuntimeException e) {
if (e.getCause() instanceof KettleException) {
log.warn("Transformation finished but an extension point plugin failed", e.getCause());
} else throw e;
} Prevention
- 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
When it happens
Trigger: A plugin registered under the KettleExtensionPoint.TransformationFinish extension point throws a KettleException inside its callExtensionPoint() implementation while Trans.executeTransformation()/run() is finishing.
Common situations: 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.
Related errors
- Unexpected error in calling extension point upon step finish
- Could not create ValueMetaInterface
- Error invoking lifecycle listener
- No compression provider found with name =
- ScriptValuesMetaMod.Exception.UnableToParseXMLforAdditionalC…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/f35c3e3364ae51fb.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/Trans.java:1501
transFinishedBlockingQueue = new ArrayBlockingQueue<>( TRANS_FINISHED_BLOCKING_QUEUE_SIZE );
TransListener transListener = new TransAdapter() {
@Override
public void transFinished( Trans trans ) {
try {
shutdownHeartbeat( trans != null ? trans.heartbeat : null );
if ( trans != null && transMeta.getParent() == null && trans.parentJob == null && trans.parentTrans == null ) {
if ( log.isDetailed() && transMeta.getMetaFileCache() != null ) {
transMeta.getMetaFileCache().logCacheSummary( log );
}
transMeta.setMetaFileCache( null );
}
ExtensionPointHandler.callExtensionPoint( log, KettleExtensionPoint.TransformationFinish.id, trans );
} catch ( KettleException e ) {
throw new RuntimeException( "Error calling extension point at end of transformation", e );
}
// First of all, stop the performance snapshot timer if there is is
// one...
//
if ( transMeta.isCapturingStepPerformanceSnapShots() && stepPerformanceSnapShotTimer != null ) {
stepPerformanceSnapShotTimer.cancel();
}
transMeta.disposeEmbeddedMetastoreProvider();
setFinished( true );
setRunning( false ); // no longer running
log.snap( Metrics.METRIC_TRANSFORMATION_EXECUTION_STOP );
// If the user ran with metrics gathering enabled and a metrics logging table is configured, add another
// listener...View on GitHub (pinned to f3058517a1)