{"record":{"id":"fe22466d96650184","repo":"pentaho/pentaho-kettle","slug":"unable-to-complete-revision-deletion","errorCode":null,"errorMessage":"Unable to complete revision deletion","messagePattern":"Unable to complete revision deletion","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/pur/core/src/main/java/com/pentaho/di/purge/UnifiedRepositoryPurgeService.java","lineNumber":123,"sourceCode":"    int i = 0;\n    int listSize = versionList.size();\n    if ( listSize > versionCount ) {\n      getLogger().info( \"version count: removing versions\" );\n    }\n    for ( VersionSummary versionSummary : versionList ) {\n      if ( i < listSize - versionCount ) {\n        Serializable versionId = versionSummary.getId();\n        getLogger().debug( \"removing version \" + versionId.toString() );\n        unifiedRepository.deleteFileAtVersion( fileId, versionId );\n        i++;\n      } else {\n        break;\n      }\n    }\n  }\n\n  private void processDeleteException( Throwable e ) throws KettleException {\n    throw new KettleException( \"Unable to complete revision deletion\", e );\n  }\n\n  public void doDeleteRevisions( PurgeUtilitySpecification purgeSpecification ) throws PurgeDeletionException {\n    if ( purgeSpecification != null ) {\n      getLogger().setCurrentFilePath( purgeSpecification.getPath() );\n      logConfiguration( purgeSpecification );\n      if ( purgeSpecification.getPath() != null && !purgeSpecification.getPath().isEmpty() ) {\n        processRevisionDeletion( purgeSpecification );\n      }\n\n      // Now do shared objects if required\n      if ( purgeSpecification.isSharedObjects() ) {\n        if ( purgeSpecification.isPurgeFiles() ) {\n          for ( String sharedObjectpath : sharedObjectFolders ) {\n            purgeSpecification.fileFilter = \"*\";\n            purgeSpecification.setPath( sharedObjectpath );\n            processRevisionDeletion( purgeSpecification );\n          }","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/pur/core/src/main/java/com/pentaho/di/purge/UnifiedRepositoryPurgeService.java#L105-L141","documentation":"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().","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the wrapped cause via exception.getCause() to find the actual repository failure","Verify repository connectivity and re-run the purge after transient network issues clear","Check that the executing user has delete permissions on all target revisions in the target path","Re-run deleteVersionsBeforeDate with a narrower date/path to isolate the failing file"],"exampleFix":"// before: blanket wrap hides root cause handling\ntry { ...delete revisions... } catch ( Throwable e ) { processDeleteException( e ); }\n// after: handle known recoverable causes before wrapping\ncatch ( Throwable e ) {\n  if ( e instanceof java.net.ConnectException ) { retryWithBackoff(); } else { processDeleteException( e ); }\n}","handlingStrategy":"try-catch","validationCode":"// verify repository reachable before purge\nif ( !repoConnectivityCheck( repositoryUrl ) ) { throw new IllegalStateException( \"Repository unreachable; aborting purge\" ); }","typeGuard":null,"tryCatchPattern":"try {\n  service.deleteVersionsBeforeDate( purgeSpec, cutoffDate );\n} catch ( KettleException e ) {\n  Throwable root = e.getCause();\n  log.error( \"Revision deletion failed due to: \" + root.getMessage(), root );\n  if ( isTransient( root ) ) { scheduleRetry(); } else { throw new PurgeFailure( root ); }\n}","preventionTips":["Always log/inspect getCause() rather than the generic message","Check repository connectivity and permissions before large purges","Run purges during low-traffic windows to reduce lock contention","Scope purges to narrow paths/dates so failures are isolatable"],"tags":["kettle","repository","revision-deletion","wrapped-exception"],"backgroundTag":"http-error-response","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"}