pentaho/pentaho-kettle · error · SftpException

Failed to delete:

Error message

Failed to delete: 

What it means

MinaSftpSession.delete() wraps IOException from the rmdir/remove path into an SftpException. Deletion failed server-side: wrong path, non-empty directory, or insufficient permission. Note the embedded isDirectory(path) call can itself throw for missing paths before delete even runs.

Solutions

  1. Check file existence before deleting and treat already-gone as success (idempotent cleanup)
  2. Empty the directory (recursively delete children) before calling delete on it
  3. Verify the SSH user has delete permission on the target and its parent
  4. Inspect e.getCause() for the SSH status code to choose the right remediation

Example fix

// before
session.delete(path);
// after
try {
  session.delete(path);
} catch (SftpException e) {
  if (!session.fileExists(path)) { log.info("Already deleted: " + path); return; }
  throw e;
}
Defensive patterns

Strategy: validation

Validate before calling

// idempotent delete: pre-check existence
boolean exists;
try { session.size(path); exists = true; } catch (SftpException e) { exists = false; }
if (exists) session.delete(path); // only delete when present

Type guard

boolean safeDelete(MinaSftpSession s, String p) {
  try { if (s.fileExists(p)) { s.delete(p); } return true; }
  catch (SftpException e) { return false; }
}

Try / catch

try {
  session.delete(path);
} catch (SftpException e) {
  Throwable c = e.getCause();
  if (c != null && String.valueOf(c.getMessage()).toLowerCase().contains("no such file")) return; // already gone
  if (session.isDirectory(path)) throw new IOException("directory not empty; empty it first: " + path, e);
  throw e;
}

Prevention

When it happens

Trigger: Calling delete(path) when the path does not exist (stat inside delete fails), deleting a non-empty directory with rmdir, lacking delete permission, or the SFTP channel erroring mid-call.

Common situations: Cleanup jobs racing with other processes that already removed the file, trying to remove directories that still contain entries, service accounts without delete rights, or double-deletion in retry logic.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSftpSession.java:133

  @Override
  public void mkdir( String path ) throws SftpException {
    try {
      client.mkdir( path );
    } catch ( IOException e ) {
      throw new SftpException( "Failed to create directory: " + path, e );
    }
  }

  @Override
  public void delete( String path ) throws SftpException {
    try {
      if ( isDirectory( path ) ) {
        client.rmdir( path );
      } else {
        client.remove( path );
      }
    } catch ( IOException e ) {
      throw new SftpException( "Failed to delete: " + path, e );
    }
  }

  @Override
  public void rename( String oldPath, String newPath ) throws SftpException {
    try {
      client.rename( oldPath, newPath );
    } catch ( IOException e ) {
      throw new SftpException( "Failed to rename from " + oldPath + " to " + newPath, e );
    }
  }

  @Override
  public void close() {
    try {
      client.close();
    } catch ( IOException ignored ) {
      // Ignore

View on GitHub (pinned to f3058517a1)