pentaho/pentaho-kettle · error · KettleException

TransMeta.Exception.PlsSelectAValidDirectoryBeforeSavingTheTransformation

TransMeta.Exception.PlsSelectAValidDirectoryBeforeSavingTheTransformation

Error message

Please select a valid directory before saving the transformation!

What it means

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.

Solutions

  1. Set a valid persisted directory before saving: transMeta.setRepositoryDirectory(repository.loadRepositoryDirectoryTree().findDirectory("/path")) .
  2. If saving a new transformation in the UI, prompt the user to pick a directory (the standard save dialog does this).
  3. Reload the directory tree from the repository and reattach it if the directory was deleted/moved.
  4. For root-level saves, use the repository's root directory object rather than a default-constructed RepositoryDirectory.

Example fix

// before
repository.save(transMeta, "comment", null, false); // directory ObjectId == null
// after
RepositoryDirectoryInterface dir = repository.loadRepositoryDirectoryTree().findDirectory("/home/dev");
transMeta.setRepositoryDirectory(dir);
repository.save(transMeta, "comment", null, false);
Defensive patterns

Strategy: validation

Validate before calling

RepositoryDirectoryInterface dir = transMeta.getRepositoryDirectory();
if (dir == null || dir.getObjectId() == null) {
  transMeta.setRepositoryDirectory(
    repository.loadRepositoryDirectoryTree().findDirectory("/home/dev"));
}

Type guard

boolean validDir = transMeta.getRepositoryDirectory() != null
  && transMeta.getRepositoryDirectory().getObjectId() != null;

Try / catch

try {
  repository.save(transMeta, comment, monitor, false);
} catch (KettleException e) {
  if (e.getMessage().contains("PlsSelectAValidDirectory")) { /* prompt user for directory */ }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/9ca1a181f5f1bc73. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryTransDelegate.java:162

   *          Overwrite existing object(s)?
   * @throws KettleException
   *           if an error occurs.
   */
  public void saveTransformation( TransMeta transMeta, String versionComment, ProgressMonitorListener monitor,
    boolean overwriteAssociated ) throws KettleException {
    try {
      if ( monitor != null ) {
        monitor.subTask( BaseMessages.getString( PKG, "TransMeta.Monitor.LockingRepository" ) );
      }

      repository.insertLogEntry( "save transformation '" + transMeta.getName() + "'" );

      // Clear attribute id cache
      repository.connectionDelegate.clearNextIDCounters(); // force repository lookup.

      // Do we have a valid directory?
      if ( transMeta.getRepositoryDirectory().getObjectId() == null ) {
        throw new KettleException( BaseMessages.getString(
          PKG, "TransMeta.Exception.PlsSelectAValidDirectoryBeforeSavingTheTransformation" ) );
      }

      int nrWorks =
        2 + transMeta.getDatabaseManagementInterface().getAll().size() + transMeta.nrNotes()
          + transMeta.nrSteps() + transMeta.nrTransHops();
      if ( monitor != null ) {
        monitor.beginTask( BaseMessages.getString( PKG, "TransMeta.Monitor.SavingTransformationTask.Title" )
          + transMeta.getPathAndName(), nrWorks );
      }
      if ( log.isDebug() ) {
        log.logDebug( BaseMessages.getString( PKG, "TransMeta.Log.SavingOfTransformationStarted" ) );
      }

      if ( monitor != null && monitor.isCanceled() ) {
        throw new KettleDatabaseException();
      }

View on GitHub (pinned to f3058517a1)