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
- 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.
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
- 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
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
- Could not find folder [ + id + ]
- Could not retrieve version history of object with path
- DELETE_JOB : repository is read-only
- " + element.getName() + " has a null id
- ERROR_0002_Cannot_Load_Job_From_Repository
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)