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
- Check file existence before deleting and treat already-gone as success (idempotent cleanup)
- Empty the directory (recursively delete children) before calling delete on it
- Verify the SSH user has delete permission on the target and its parent
- 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
- Make delete idempotent — missing target should be success in cleanup jobs
- Empty directories before rmdir (SFTP rmdir fails on non-empty dirs)
- Verify delete permission on the target and its parent for the SSH user
- Serialize cleanup with other processes to avoid double-deletion races
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
- Failed to create directory:
- Failed to upload file:
- Failed to check if path is directory:
- Failed to download file:
- Failed to get file size:
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 ) {
// IgnoreView on GitHub (pinned to f3058517a1)