pentaho/pentaho-kettle · error · KettleException

Unable to complete revision deletion

Error message

Unable to complete revision deletion

What it means

UnifiedRepositoryPurgeService.processDeleteException is the single wrapping point for any Throwable raised while deleting repository revisions. It rethrows the original cause (e.g. a repository connectivity or permission error) inside a KettleException with the generic message 'Unable to complete revision deletion', so the real reason is always in getCause().

Solutions

  1. Inspect the wrapped cause via exception.getCause() to find the actual repository failure
  2. Verify repository connectivity and re-run the purge after transient network issues clear
  3. Check that the executing user has delete permissions on all target revisions in the target path
  4. Re-run deleteVersionsBeforeDate with a narrower date/path to isolate the failing file

Example fix

// before: blanket wrap hides root cause handling
try { ...delete revisions... } catch ( Throwable e ) { processDeleteException( e ); }
// after: handle known recoverable causes before wrapping
catch ( Throwable e ) {
  if ( e instanceof java.net.ConnectException ) { retryWithBackoff(); } else { processDeleteException( e ); }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify repository reachable before purge
if ( !repoConnectivityCheck( repositoryUrl ) ) { throw new IllegalStateException( "Repository unreachable; aborting purge" ); }

Try / catch

try {
  service.deleteVersionsBeforeDate( purgeSpec, cutoffDate );
} catch ( KettleException e ) {
  Throwable root = e.getCause();
  log.error( "Revision deletion failed due to: " + root.getMessage(), root );
  if ( isTransient( root ) ) { scheduleRetry(); } else { throw new PurgeFailure( root ); }
}

Prevention

When it happens

Trigger: deleteVersionsBeforeDate() performs revision deletion per file/version; any exception thrown by the underlying repository delete calls is passed to processDeleteException and wrapped in a KettleException.

Common situations: Repository outages or dropped connections mid-purge; insufficient permissions to delete specific revisions; files locked or referenced by shared objects; concurrent purge runs causing optimistic-lock failures.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at plugins/pur/core/src/main/java/com/pentaho/di/purge/UnifiedRepositoryPurgeService.java:123

    int i = 0;
    int listSize = versionList.size();
    if ( listSize > versionCount ) {
      getLogger().info( "version count: removing versions" );
    }
    for ( VersionSummary versionSummary : versionList ) {
      if ( i < listSize - versionCount ) {
        Serializable versionId = versionSummary.getId();
        getLogger().debug( "removing version " + versionId.toString() );
        unifiedRepository.deleteFileAtVersion( fileId, versionId );
        i++;
      } else {
        break;
      }
    }
  }

  private void processDeleteException( Throwable e ) throws KettleException {
    throw new KettleException( "Unable to complete revision deletion", e );
  }

  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 );
          }

View on GitHub (pinned to f3058517a1)