java-native-access/jna · error · IllegalArgumentException
destDir must be a directory.
Error message
destDir must be a directory.
What it means
Advapi32Util.backupEncryptedFile(File src, File destDir) backs up an EFS-encrypted file via the Win32 OpenEncryptedFileRaw/ReadEncryptedFileRaw API, which requires a destination directory to write the backup into. If destDir does not exist or is a regular file, the method throws IllegalArgumentException('destDir must be a directory.') before starting the backup.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java:3134
}
}
/**
* Backup an encrypted file or folder without decrypting it. A file named
* "bar/sample.text" will be backed-up to "destDir/sample.text". A directory
* named "bar" will be backed-up to "destDir/bar". This method is NOT
* recursive. If you have an encrypted directory with encrypted files, this
* method must be called once for the directory, and once for each encrypted
* file to be backed-up.
*
* @param src
* The encrypted file or directory to backup.
* @param destDir
* The directory where the backup will be saved.
*/
public static void backupEncryptedFile(File src, File destDir) {
if (!destDir.isDirectory()) {
throw new IllegalArgumentException("destDir must be a directory.");
}
ULONG readFlag = new ULONG(0); // Open the file for export (backup)
ULONG writeFlag = new ULONG(CREATE_FOR_IMPORT); // Import (restore) file
if (src.isDirectory()) {
writeFlag.setValue(CREATE_FOR_IMPORT | CREATE_FOR_DIR);
}
// open encrypted file for export
String srcFileName = src.getAbsolutePath();
PointerByReference pvContext = new PointerByReference();
if (Advapi32.INSTANCE.OpenEncryptedFileRaw(srcFileName, readFlag,
pvContext) != W32Errors.ERROR_SUCCESS) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
// read encrypted fileView on GitHub (pinned to d036ad9781)
Solutions
- Create the destination directory before the call: if (!destDir.exists()) destDir.mkdirs();
- Pass the parent directory (destDir) not the output file path; the method writes the backup into the directory itself.
- Verify with destDir.isDirectory() and correct the path (check for typos, drive letters, UNC paths).
- If destDir is a file, delete or rename it and create a directory with the same path.
Example fix
// before
Advapi32Util.backupEncryptedFile(src, new File("C:\\backup\\out.dat"));
// after
File destDir = new File("C:\\backup");
if (!destDir.isDirectory()) {
destDir.mkdirs();
}
Advapi32Util.backupEncryptedFile(src, destDir); Defensive patterns
Strategy: validation
Validate before calling
if (destDir == null || !destDir.isDirectory()) {
throw new IllegalArgumentException("destDir must be an existing directory: " + destDir);
} Type guard
boolean isWritableDirectory(File dir) {
return dir != null && dir.isDirectory() && dir.canWrite();
} Try / catch
try {
Advapi32Util.backupEncryptedFile(src, destDir);
} catch (IllegalArgumentException e) {
log.error("Bad destination for EFS backup: " + e.getMessage());
} Prevention
- Call destDir.mkdirs() when the directory does not exist, before the backup.
- Pass the containing directory, not the intended backup file path.
- Verify with destDir.isDirectory() (not exists(), which is true for files too).
- Check dir.canWrite() to ensure the backup will not fail mid-write on permissions.
When it happens
Trigger: Calling backupEncryptedFile with a destDir path that does not exist, points to a file instead of a directory, or is a stale path (deleted after creation).
Common situations: Typo'd or uncreated output folder; passing the intended output file path rather than the containing directory; running the backup before the destination mount/dir is prepared; path separator confusion on Windows.
Related errors
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
- Expected GetTokenInformation to fail with ERROR_INSUFFICIENT
- Unexpected registry type + lpType.getValue() + , expected RE
- Invalid type:
- SECURITY_DESCRIPTOR_RELATIVE does not contain owner
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/47324bea80e0e401.
Report an issue: GitHub.