pentaho/pentaho-kettle · error · KettleException
Directory cannot become a child to itself
Error message
Directory cannot become a child to itself
What it means
Thrown by renameDirectory when the target parent directory is a descendant of the directory being moved, which would create a cycle in the directory tree. The method loads the subtree of id_directory and checks findDirectory(id_directory_parent); a non-null result means the parent lives inside the directory being moved. Thrown before any database mutation.
Solutions
- Before moving, verify the new parent is not inside the source subtree (walk the parent chain of newParent and compare ObjectIds)
- Choose a target parent outside the moved directory's subtree
- In UIs, visually disable drop targets that are descendants of the dragged node
Example fix
// before
repo.renameRepositoryDirectory( dirAId, repo.findDirectory( "/a/b" ), null ); // /a/b is inside /a -> throws
// after
RepositoryDirectoryInterface newParent = repo.findDirectory( "/a/b" );
boolean inside = false;
for ( RepositoryDirectoryInterface p = newParent; p != null; p = p.getParent() ) {
if ( p.getObjectId().equals( dirAId ) ) { inside = true; break; }
}
if ( !inside ) repo.renameRepositoryDirectory( dirAId, newParent, null ); Defensive patterns
Strategy: validation
Validate before calling
boolean isDescendant( RepositoryDirectoryInterface candidateChild, ObjectId ancestorId ) {
for ( RepositoryDirectoryInterface p = candidateChild; p != null; p = p.getParent() ) {
if ( p.getObjectId().equals( ancestorId ) ) return true;
}
return false;
}
// reject move if isDescendant( newParentDir, dirId ) Type guard
boolean canMoveInto( ObjectId dirId, RepositoryDirectoryInterface newParent ) {
ObjectId p = newParent == null ? null : newParent.getObjectId();
while ( p != null ) {
if ( p.equals( dirId ) ) return false;
p = parentOf( p );
}
return true;
} Prevention
- Walk the new parent's ancestor chain and reject if it contains the moved directory
- In tree UIs, disable drop targets that are descendants of the dragged node
- Validate moves in scripted reorganizations before executing them
When it happens
Trigger: repository.renameRepositoryDirectory(id, newParent, name) where newParent is a subdirectory (at any depth) of the directory identified by id, e.g. moving /a into /a/b.
Common situations: Recursive or scripted reorganization of transformation/job folders that accidentally moves a parent into its own child; drag-and-drop in Spoon dropping a folder onto one of its descendants.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Failed to copy directory into itself
- A connection of type PALO is expected
- A connection of type PALO is expected
- A server socket allocation always has to accompanied by a…
- A server socket allocation always has to accompanied by…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/3449fab423ed50f1.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryDirectoryDelegate.java:221
* @param id_directory
* Id of the directory to be moved/renamed
* @param id_directory_parent
* Id of the new parent directory (null if the parent does not change)
* @param newName
* New name for this directory (null if the name does not change)
* @throws KettleException
*/
public synchronized void renameDirectory( ObjectId id_directory, ObjectId id_directory_parent, String newName ) throws KettleException {
if ( id_directory.equals( id_directory_parent ) ) {
// Make sure the directory cannot become its own parent
throw new KettleException( "Failed to copy directory into itself" );
} else {
// Make sure the directory does not become a descendant of itself
RepositoryDirectory rd = new RepositoryDirectory();
loadRepositoryDirectory( rd, id_directory );
if ( rd.findDirectory( id_directory_parent ) != null ) {
// The parent directory is a child of this directory. Do not proceed
throw new KettleException( "Directory cannot become a child to itself" );
} else {
// Check for duplication
RepositoryDirectory newParent = new RepositoryDirectory();
loadRepositoryDirectory( newParent, id_directory_parent );
RepositoryDirectory child = newParent.findChild( newName == null ? rd.getName() : newName );
if ( child != null ) {
throw new KettleException( "Destination directory already contains a diectory with requested name" );
}
}
}
if ( id_directory_parent != null || newName != null ) {
RowMetaAndData r = new RowMetaAndData();
String sql = "UPDATE " + quoteTable( KettleDatabaseRepository.TABLE_R_DIRECTORY ) + " SET ";
boolean additionalParameter = false;
if ( newName != null ) {View on GitHub (pinned to f3058517a1)