java-native-access/jna · error · Win32Exception
Win32Exception(Kernel32.INSTANCE.GetLastError())
Error message
Win32Exception(Kernel32.INSTANCE.GetLastError())
What it means
After calling NetGetDCName, getDCName frees the native buffer with NetApiBufferFree in a finally block. If the free call itself fails, the resulting GetLastError() code is wrapped in a Win32Exception and thrown. Note this can mask the original return value or any in-flight exception from the try block.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Netapi32Util.java:128
* @param serverName
* Specifies the DNS or NetBIOS name of the remote server on which the function is
* to execute.
* @param domainName
* Specifies the name of the domain.
* @return
* Name of the primary domain controller.
*/
public static String getDCName(String serverName, String domainName) {
PointerByReference bufptr = new PointerByReference();
try {
int rc = Netapi32.INSTANCE.NetGetDCName(serverName, domainName, bufptr);
if (LMErr.NERR_Success != rc) {
throw new Win32Exception(rc);
}
return bufptr.getValue().getWideString(0);
} finally {
if (W32Errors.ERROR_SUCCESS != Netapi32.INSTANCE.NetApiBufferFree(bufptr.getValue())) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
}
/**
* Return the domain/workgroup join status for a computer.
* @return Join status.
*/
public static int getJoinStatus() {
return getJoinStatus(null);
}
/**
* Return the domain/workgroup join status for a computer.
* @param computerName Computer name.
* @return Join status.
*/
public static int getJoinStatus(String computerName) {View on GitHub (pinned to d036ad9781)
Solutions
- Treat this exception as secondary: the real failure is usually in NetGetDCName; capture and log both errors.
- Guard the finally block: only free when bufptr.getValue() != Pointer.NULL.
- Upgrade JNA — newer versions harden these cleanup paths against NULL buffers.
- If it persists, check for heap/native memory corruption elsewhere in the process.
Example fix
// before
} finally {
if (W32Errors.ERROR_SUCCESS != Netapi32.INSTANCE.NetApiBufferFree(bufptr.getValue())) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
// after
} finally {
if (bufptr.getValue() != Pointer.NULL
&& W32Errors.ERROR_SUCCESS != Netapi32.INSTANCE.NetApiBufferFree(bufptr.getValue())) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Only call getDCName when it can succeed; a failed call is what corrupts cleanup PointerByReference bufptr = new PointerByReference(); int rc = Netapi32.INSTANCE.NetGetDCName(null, domain, bufptr); boolean ok = (rc == LMErr.NERR_Success) && bufptr.getValue() != Pointer.NULL;
Try / catch
try {
return Netapi32Util.getDCName(server, domain);
} catch (Win32Exception e) {
LOG.warn("getDCName/cleanup failed, rc=" + e.getErrorCode());
return null; // treat as 'no DC available'
} Prevention
- Upgrade JNA — newer releases guard the buffer-free path against NULL pointers.
- Never ignore the primary getDCName failure; this cleanup error usually stems from it.
- Pin a single JNA version to avoid duplicate native library loads.
- If seen on successful calls, audit the process for native heap corruption.
When it happens
Trigger: NetApiBufferFree returns non-ERROR_SUCCESS while cleaning up the DC-name buffer — e.g. bufptr.getValue() is NULL because NetGetDCName failed and never allocated a buffer, or the pointer is already invalid.
Common situations: getDCName failing (e.g. no DC found) so the finally block frees a NULL/invalid pointer and throws a second, confusing exception that hides the real cause.
Related errors
- Win32Exception(rc)
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
- Expected GetTokenInformation to fail with ERROR_INSUFFICIENT
- Failed to find privilege "{privilege}" - {GetLastError}
- Win32Exception from native GetLastError after GetPrivateProf
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/1118e1264d90860e.
Report an issue: GitHub.