pentaho/pentaho-kettle · error · PurgeDeletionException
Must purge files before shared objects
Error message
Must purge files before shared objects
What it means
doDeleteRevisions throws PurgeDeletionException('Must purge files before shared objects') to enforce purge ordering: regular files must be purged before shared-object folders. When the purge specification requests shared-object deletion without having performed/allowed the preceding file purge pass, the service aborts rather than leaving dangling references.
Solutions
- Run the purge in two ordered phases: purge regular files first, then shared object folders
- Update the PurgeUtilitySpecification so the file-purge phase flag is enabled before the shared-objects phase
- Remove the shared-object-only request and purge the parent files together with their shared objects
- Check purge logs to confirm the file phase completed before the shared-object phase started
Example fix
// before: shared objects only purgeSpec.setPath( sharedObjectPath ); service.doDeleteRevisions( purgeSpec ); // after: purge files first, then shared objects purgeSpec.setPath( filePath ); service.doDeleteRevisions( purgeSpec ); purgeSpec.setPath( sharedObjectPath ); service.doDeleteRevisions( purgeSpec );
Defensive patterns
Strategy: validation
Validate before calling
if ( purgeTargetsSharedObjects( purgeSpec ) && !filesPurgedFirst( purgeSpec ) ) {
throw new IllegalStateException( "Purge regular files before shared object folders." );
} Try / catch
try {
service.doDeleteRevisions( purgeSpec );
} catch ( PurgeDeletionException e ) {
if ( e.getMessage().contains( "shared objects" ) ) {
runFilePurgePhase();
service.doDeleteRevisions( purgeSpec );
} else { throw e; }
} Prevention
- Always execute the file purge phase before the shared-objects phase
- Encode the two-phase order in your purge driver code
- Review PurgeUtilitySpecification flags to ensure the file phase isn't skipped
- Test purge flows on a sandbox repository before production
When it happens
Trigger: Calling doDeleteRevisions (via doPurgeUtilSharedObjectsTest-style specifications) where shared object folders are present but the flag/branch indicating files were already purged (the if preceding the else at line 143) is false.
Common situations: Purging only shared objects while regular files still contain revisions referencing them; misconfigured PurgeUtilitySpecification that skips the file-purge phase; users selecting shared-object cleanup expecting it to work standalone.
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
- " + element.getName() + " has a null id
- JobMeta.Log.UnableToReadDatabasesFromRepository
- TransMeta.Log.UnableToReadDatabaseIDSFromRepository
- TransMeta.Log.UnableToReadDatabasesFromRepository
- Unable to load shared objects
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/433618aac1c76345.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/pur/core/src/main/java/com/pentaho/di/purge/UnifiedRepositoryPurgeService.java:143
public void doDeleteRevisions( PurgeUtilitySpecification purgeSpecification ) throws PurgeDeletionException {
if ( purgeSpecification != null ) {
getLogger().setCurrentFilePath( purgeSpecification.getPath() );
logConfiguration( purgeSpecification );
if ( purgeSpecification.getPath() != null && !purgeSpecification.getPath().isEmpty() ) {
processRevisionDeletion( purgeSpecification );
}
// Now do shared objects if required
if ( purgeSpecification.isSharedObjects() ) {
if ( purgeSpecification.isPurgeFiles() ) {
for ( String sharedObjectpath : sharedObjectFolders ) {
purgeSpecification.fileFilter = "*";
purgeSpecification.setPath( sharedObjectpath );
processRevisionDeletion( purgeSpecification );
}
} else {
throw new PurgeDeletionException( "Must purge files before shared objects" );
}
}
}
}
private void processRevisionDeletion( PurgeUtilitySpecification purgeSpecification ) throws PurgeDeletionException {
RepositoryRequest repositoryRequest =
new RepositoryRequest( purgeSpecification.getPath(), true, -1, purgeSpecification.getFileFilter() );
repositoryRequest.setTypes( FILES_TYPE_FILTER.FILES_FOLDERS );
repositoryRequest.setIncludeMemberSet( new HashSet<String>( Arrays.asList( new String[] { "name", "id", "folder",
"path", "versioned", "versionId", "locked" } ) ) );
getLogger().debug( "Creating file list" );
RepositoryFileTreeDto tree = getRepoWs().getTreeFromRequest( repositoryRequest );
processPurgeForTree( tree, purgeSpecification );
}View on GitHub (pinned to f3058517a1)