{"record":{"id":"6344cabfcef4caa3","repo":"pentaho/pentaho-kettle","slug":"transmeta-log-usercancelledtranssave","errorCode":"TransMeta.Log.UserCancelledTransSave","errorMessage":"User canceled saving of transformation.","messagePattern":"User canceled saving of transformation\\.","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"warning","filePath":"engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryTransDelegate.java","lineNumber":221,"sourceCode":"        }\n        if ( log.isDebug() ) {\n          log.logDebug( BaseMessages.getString( PKG, \"TransMeta.Log.DeletingOldVersionTransformation\" ) );\n        }\n        repository.deleteTransformation( transMeta.getObjectId() );\n        if ( log.isDebug() ) {\n          log.logDebug( BaseMessages.getString( PKG, \"TransMeta.Log.OldVersionOfTransformationRemoved\" ) );\n        }\n      }\n      if ( monitor != null ) {\n        monitor.worked( 1 );\n      }\n\n      if ( log.isDebug() ) {\n        log.logDebug( BaseMessages.getString( PKG, \"TransMeta.Log.SavingNotes\" ) );\n      }\n      for ( int i = 0; i < transMeta.nrNotes(); i++ ) {\n        if ( monitor != null && monitor.isCanceled() ) {\n          throw new KettleDatabaseException( BaseMessages.getString( PKG, \"TransMeta.Log.UserCancelledTransSave\" ) );\n        }\n\n        // if (monitor != null) monitor.subTask(BaseMessages.getString(PKG, \"TransMeta.Monitor.SavingNoteTask.Title\") +\n        // (i + 1) + \"/\" + transMeta.nrNotes());\n        NotePadMeta ni = transMeta.getNote( i );\n        repository.saveNotePadMeta( ni, transMeta.getObjectId() );\n        if ( ni.getObjectId() != null ) {\n          repository.insertTransNote( transMeta.getObjectId(), ni.getObjectId() );\n        }\n        if ( monitor != null ) {\n          monitor.worked( 1 );\n        }\n      }\n\n      if ( log.isDebug() ) {\n        log.logDebug( BaseMessages.getString( PKG, \"TransMeta.Log.SavingDatabaseConnections\" ) );\n      }\n      for ( DatabaseMeta databaseMeta : transMeta.getDatabaseManagementInterface().getAll() ) {","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryTransDelegate.java#L203-L239","documentation":"While saving notes during saveTransformation(), the delegate checks the progress monitor before each note and throws a KettleDatabaseException 'User canceled saving of transformation.' when monitor.isCanceled() is true. This is a deliberate cancellation signal, not a database failure, despite the exception type.","triggerScenarios":"repository.save(transMeta, comment, monitor, overwrite) with a ProgressMonitor that the user pressed Cancel on while the notes loop (transMeta.nrNotes()) is iterating.","commonSituations":"User cancels the save progress dialog of a big transformation; UI timeout/cancel button triggers monitor cancellation mid-save; automated callers pass a monitor that is canceled from the start.","solutions":["This is expected user behavior — catch KettleDatabaseException whose message is the cancellation key and treat it as a normal cancel, not an error.","Ensure the transformation remains loadable: a canceled save can leave partial rows; delete or re-save the transformation afterward.","If cancels are unintentional, don't pass an already-canceled monitor, or pass null when no progress reporting is needed.","Inform the user the save was not completed before they close the transformation."],"exampleFix":"// before\nrepository.save(transMeta, \"c\", monitor, false);\n// after\ntry {\n  repository.save(transMeta, \"c\", monitor, false);\n} catch (KettleDatabaseException e) {\n  if (monitor != null && monitor.isCanceled()) {\n    log.logBasic(\"Save cancelled by user\");\n    return; // treat as cancel, not failure\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (monitor != null && monitor.isCanceled()) return; // don't start a doomed save","typeGuard":null,"tryCatchPattern":"try {\n  repository.save(transMeta, comment, monitor, false);\n} catch (KettleDatabaseException e) {\n  if (monitor != null && monitor.isCanceled()) return; // user cancel\n  throw e;\n}","preventionTips":["Never pass a pre-canceled monitor","Treat cancellation messages as normal flow, not DB failures","Warn users that canceling mid-save leaves partial rows"],"tags":["repository","pentaho-kettle","user-cancel","progress-monitor"],"backgroundTag":"operation-cancelled","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"}