{"record":{"id":"fa93da496d8e2033","repo":"pentaho/pentaho-kettle","slug":"illegal-move-target","errorCode":null,"errorMessage":"Illegal move target","messagePattern":"Illegal move target","errorType":"exception","errorClass":"FileSystemException","httpStatus":null,"severity":"error","filePath":"plugins/repo-vfs/repo-vfs-ws/src/main/java/org/pentaho/di/plugins/repovfs/ws/vfs/JCRSolutionFileObject.java","lineNumber":353,"sourceCode":"    return Objects.equal( file1.getName().getExtension(), file2.getName().getExtension() );\n  }\n\n  private static String getNameNoExt( FileObject file ) {\n    return FilenameUtils.removeExtension( file.getName().getBaseName() );\n  }\n\n  /** Rename this file in place */\n  private void callRepoRename( String newName ) throws RepositoryClientException {\n    String[] origPath = computeFileNames( getName() );\n    log.debug( \"Optimized rename call\" );\n    repoClient.rename( origPath, newName );\n  }\n\n  /** Move this to a different parent */\n  private void callRepoMove( FileObject targetFolder ) throws FileSystemException, RepositoryClientException {\n    if ( targetFolder == null ) {\n      // beyond root\n      throw new FileSystemException( \"Illegal move target\" );\n    }\n    if ( !targetFolder.exists() ) {\n      log.debug( \"Creating target folder {} for move\", targetFolder.getName() );\n      targetFolder.createFolder();\n    }\n    RepositoryFileDto thisFile = getFileDto();\n    String[] destPath = computeFileNames( targetFolder.getName() );\n    log.debug( \"Optimized move call\" );\n    repoClient.moveTo( thisFile, destPath );\n  }\n\n  private static boolean haveSameName( FileObject file1, FileObject file2 ) {\n    return file1.getName().getBaseName().equals( file2.getName().getBaseName() );\n  }\n\n  private static boolean haveSameParent( FileObject file1, FileObject file2 ) throws FileSystemException {\n    FileObject parent1 = file1.getParent();\n    FileObject parent2 = file2.getParent();","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/repo-vfs/repo-vfs-ws/src/main/java/org/pentaho/di/plugins/repovfs/ws/vfs/JCRSolutionFileObject.java#L335-L371","documentation":"JCRSolutionFileObject.callRepoMove refuses to move a file when the target folder is null, which happens when the computed destination lies beyond the repository root. It throws a plain FileSystemException('Illegal move target') before any repository call is made. This is a client-side guard against a malformed move destination.","triggerScenarios":"Calling fileObject.moveTo(target) where resolving the target's parent yields null — i.e. attempting to move a folder (typically a top-level folder) to a parent above the repository root.","commonSituations":"Programmatic renames/moves that compute the destination path by stripping a path segment, accidentally producing a root-level or above-root target; UI drag-and-drop moving a top-level folder onto the root.","solutions":["Validate that the target's parent resolves to an existing folder inside the repository before calling moveTo","Skip or reject moves whose target parent is null (beyond root) instead of attempting them","Compute the target via another valid FileObject rather than string-manipulating paths"],"exampleFix":"// before\nFileObject dest = fs.resolveFile( parentPathOf( src ) ); // may be beyond root\nsrc.moveTo( dest );\n// after\nFileObject dest = fs.resolveFile( parentPathOf( src ) );\nif ( dest == null || dest.getParent() == null ) {\n  throw new IllegalArgumentException( \"Move target must be inside the repository\" );\n}\nsrc.moveTo( dest );","handlingStrategy":"validation","validationCode":"// validate before moveTo\nboolean isValidMoveTarget( FileObject target ) throws FileSystemException {\n  if ( target == null ) return false;\n  FileObject parent = target.getParent();\n  return parent != null && parent.exists();\n}","typeGuard":"FileObject requireInsideRepository( FileObject target ) throws FileSystemException {\n  FileObject parent = ( target == null ) ? null : target.getParent();\n  if ( parent == null ) throw new IllegalArgumentException( \"Move target must be inside the repository\" );\n  return target;\n}","tryCatchPattern":"try {\n  src.moveTo( target );\n} catch ( FileSystemException e ) {\n  if ( \"Illegal move target\".equals( e.getMessage() ) ) {\n    // reject operation in UI/log instead of crashing\n  } else { throw e; }\n}","preventionTips":["Never compute move targets by raw string manipulation of repository paths","Always resolve the destination parent as a FileObject and check it exists","Reject moves whose destination is at or above the repository root"],"tags":["vfs","file-move","validation"],"backgroundTag":"invalid-argument-value","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"}