java-native-access/jna · error · Win32Exception
Win32Exception from native GetLastError after GetPrivateProf
Error message
Win32Exception from native GetLastError after GetPrivateProfileSection returned 0
What it means
getPrivateProfileSection reads all key=value entries of one INI section via the Win32 GetPrivateProfileSection API. If the native call reports a returned size of 0, the wrapper calls GetLastError; ERROR_SUCCESS means a genuinely empty section (returned as an empty array), but any other error code is wrapped in a Win32Exception and thrown. This means Windows itself reported a concrete failure reading the section, not merely an empty result.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java:796
* <p>
* This operation is atomic; no updates to the specified initialization file are allowed while this method is executed.
* </p>
*
* @param appName
* The name of the section in the initialization file.
* @param fileName
* The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the
* Windows directory.
* @return The key name and value pairs associated with the named section.
*/
public static final String[] getPrivateProfileSection(final String appName, final String fileName) {
final char buffer[] = new char[32768]; // Maximum section size according to MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724348(v=vs.85).aspx)
if (Kernel32.INSTANCE.GetPrivateProfileSection(appName, buffer, new DWORD(buffer.length), fileName).intValue() == 0) {
final int lastError = Kernel32.INSTANCE.GetLastError();
if (lastError == Kernel32.ERROR_SUCCESS) {
return EMPTY_STRING_ARRAY;
} else {
throw new Win32Exception(lastError);
}
}
return new String(buffer).split("\0");
}
/**
* Retrieves the names of all sections in an initialization file.
* <p>
* This operation is atomic; no updates to the initialization file are allowed while this method is executed.
* </p>
*
* @param fileName
* The name of the initialization file. If this parameter is {@code NULL}, the function searches the Win.ini file. If this parameter does not
* contain a full path to the file, the system searches for the file in the Windows directory.
* @return the section names associated with the named file.
*/
public static final String[] getPrivateProfileSectionNames(final String fileName) {
final char buffer[] = new char[65536]; // Maximum INI file size according to MSDN (http://support.microsoft.com/kb/78346)View on GitHub (pinned to d036ad9781)
Solutions
- Verify the fileName path is absolute and the INI file actually exists (File.exists()/canRead()) before calling.
- Confirm the exact section (appName) exists in the file; remember missing sections are also reported as error by some Windows versions.
- Catch Win32Exception and inspect its ErrorCode (e.g. ERROR_FILE_NOT_FOUND=2) to branch on the real cause instead of guessing.
- If the INI exceeds 32768 chars, split it or read via a different mechanism.
Example fix
// before
String[] entries = Kernel32Util.getPrivateProfileSection("Settings", "config.ini");
// after
File ini = new File("C:/app/config.ini");
if (!ini.isFile()) {
throw new FileNotFoundException("Missing INI: " + ini);
}
try {
String[] entries = Kernel32Util.getPrivateProfileSection("Settings", ini.getAbsolutePath());
} catch (Win32Exception e) {
if (e.getErrorCode() == WinError.ERROR_FILE_NOT_FOUND) {
entries = new String[0]; // default config
} else {
throw e;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
File ini = new File(fileName);
if (!ini.isFile() || !ini.canRead()) {
throw new FileNotFoundException(fileName);
} Try / catch
try {
return Kernel32Util.getPrivateProfileSection(appName, fileName);
} catch (Win32Exception e) {
if (e.getErrorCode() == WinError.ERROR_FILE_NOT_FOUND) {
return new String[0];
}
throw e;
} Prevention
- Always pass an absolute path to the INI file.
- Check File.exists()/canRead() before every call.
- Log Win32Exception.getErrorCode() to identify the native cause.
- Keep INI files under 32KB to fit the fixed buffer.
When it happens
Trigger: Calling Kernel32Util.getPrivateProfileSection(appName, fileName) when GetPrivateProfileSection returns 0 and GetLastError is not ERROR_SUCCESS — typically the INI file does not exist or is unreadable, the appName section is missing, the file exceeds the 32768-char buffer, or access to the file/Windows directory is denied.
Common situations: Deploying an app whose .ini config file was never copied to the expected path; using a relative path that resolves against the Windows directory instead of the app directory; section name typo (names are case-insensitive but must exist); running under an account lacking read access to the file; INI files >32KB truncated by the fixed buffer.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Win32Exception from native GetLastError after GetPrivateProf
- Win32Exception from native GetLastError after WritePrivatePr
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
- Expected GetTokenInformation to fail with ERROR_INSUFFICIENT
- Failed to find privilege "{privilege}" - {GetLastError}
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/234b937597432c5c.
Report an issue: GitHub.