{"record":{"id":"9ca1a181f5f1bc73","repo":"pentaho/pentaho-kettle","slug":"transmeta-exception","errorCode":"TransMeta.Exception.PlsSelectAValidDirectoryBeforeSavingTheTransformation","errorMessage":"Please select a valid directory before saving the transformation!","messagePattern":"Please select a valid directory before saving the transformation!","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryTransDelegate.java","lineNumber":162,"sourceCode":"   *          Overwrite existing object(s)?\n   * @throws KettleException\n   *           if an error occurs.\n   */\n  public void saveTransformation( TransMeta transMeta, String versionComment, ProgressMonitorListener monitor,\n    boolean overwriteAssociated ) throws KettleException {\n    try {\n      if ( monitor != null ) {\n        monitor.subTask( BaseMessages.getString( PKG, \"TransMeta.Monitor.LockingRepository\" ) );\n      }\n\n      repository.insertLogEntry( \"save transformation '\" + transMeta.getName() + \"'\" );\n\n      // Clear attribute id cache\n      repository.connectionDelegate.clearNextIDCounters(); // force repository lookup.\n\n      // Do we have a valid directory?\n      if ( transMeta.getRepositoryDirectory().getObjectId() == null ) {\n        throw new KettleException( BaseMessages.getString(\n          PKG, \"TransMeta.Exception.PlsSelectAValidDirectoryBeforeSavingTheTransformation\" ) );\n      }\n\n      int nrWorks =\n        2 + transMeta.getDatabaseManagementInterface().getAll().size() + transMeta.nrNotes()\n          + transMeta.nrSteps() + transMeta.nrTransHops();\n      if ( monitor != null ) {\n        monitor.beginTask( BaseMessages.getString( PKG, \"TransMeta.Monitor.SavingTransformationTask.Title\" )\n          + transMeta.getPathAndName(), nrWorks );\n      }\n      if ( log.isDebug() ) {\n        log.logDebug( BaseMessages.getString( PKG, \"TransMeta.Log.SavingOfTransformationStarted\" ) );\n      }\n\n      if ( monitor != null && monitor.isCanceled() ) {\n        throw new KettleDatabaseException();\n      }\n","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryTransDelegate.java#L144-L180","documentation":"At the start of saveTransformation(), the delegate verifies that the transformation's repository directory has a persisted ObjectId. If transMeta.getRepositoryDirectory().getObjectId() is null, the directory is not a real repository location, and a KettleException 'Please select a valid directory before saving the transformation!' is thrown. It prevents saving a transformation to an undefined location.","triggerScenarios":"repository.save(transMeta, versionComment, monitor, permissions) (which calls saveTransformation) when the TransMeta's repository directory was never set or points to a virtual/unpersisted directory — e.g. a newly created RepositoryDirectory not yet stored, or the transformation was created in code without a repository directory.","commonSituations":"Programmatically building a TransMeta and calling repository.save() without setRepositoryDirectory(); UI user never chose a directory; directory was deleted by another user while the transformation stayed open.","solutions":["Set a valid persisted directory before saving: transMeta.setRepositoryDirectory(repository.loadRepositoryDirectoryTree().findDirectory(\"/path\")) .","If saving a new transformation in the UI, prompt the user to pick a directory (the standard save dialog does this).","Reload the directory tree from the repository and reattach it if the directory was deleted/moved.","For root-level saves, use the repository's root directory object rather than a default-constructed RepositoryDirectory."],"exampleFix":"// before\nrepository.save(transMeta, \"comment\", null, false); // directory ObjectId == null\n// after\nRepositoryDirectoryInterface dir = repository.loadRepositoryDirectoryTree().findDirectory(\"/home/dev\");\ntransMeta.setRepositoryDirectory(dir);\nrepository.save(transMeta, \"comment\", null, false);","handlingStrategy":"validation","validationCode":"RepositoryDirectoryInterface dir = transMeta.getRepositoryDirectory();\nif (dir == null || dir.getObjectId() == null) {\n  transMeta.setRepositoryDirectory(\n    repository.loadRepositoryDirectoryTree().findDirectory(\"/home/dev\"));\n}","typeGuard":"boolean validDir = transMeta.getRepositoryDirectory() != null\n  && transMeta.getRepositoryDirectory().getObjectId() != null;","tryCatchPattern":"try {\n  repository.save(transMeta, comment, monitor, false);\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"PlsSelectAValidDirectory\")) { /* prompt user for directory */ }\n  throw e;\n}","preventionTips":["Always set a persisted directory before repository.save()","Obtain directories from the loaded repository tree, never new RepositoryDirectory()","Prompt users for a save location when creating transformations programmatically"],"tags":["repository","pentaho-kettle","validation","directory"],"backgroundTag":"missing-required-argument","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"}