java-native-access/jna · warning
JNA: error converting error message: %d
Error message
JNA: error converting error message: %d
What it means
On Windows, w32_format_error converts a system error code to text via FormatMessageW then WideCharToMultiByte(CP_UTF8). If the wide->UTF-8 conversion fails, JNA prints this message with GetLastError, frees the buffer, and continues with buf = NULL so the caller gets no error text. The original OS error code is still reported; only its human-readable message is lost.
Source
Thrown at native/dispatch.c:294
typedef void (JNICALL* release_t)(JNIEnv*,jarray,void*,jint);
#ifdef _WIN32
static char*
w32_format_error(int err) {
wchar_t* wbuf = NULL;
char* buf = NULL;
int wlen =
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_IGNORE_INSERTS
|FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, err, 0, (LPWSTR)&wbuf, 0, NULL);
if (wlen > 0) {
int bufSize = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL, NULL);
buf = (char*)malloc(bufSize);
int result = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, bufSize, NULL, NULL);
if (result == 0) {
fprintf(stderr, "JNA: error converting error message: %d\n", (int)GET_LAST_ERROR());
free(buf);
buf = NULL;
}
}
if (wbuf) {
LocalFree(wbuf);
}
return buf;
}
static wchar_t*
w32_short_name(JNIEnv* env, jstring str) {
wchar_t* wstr = newWideCString(env, str);
if (wstr && *wstr) {
DWORD required;
size_t size = wcslen(wstr) + 5;
wchar_t* prefixed = (wchar_t*)alloca(sizeof(wchar_t) * size);
View on GitHub (pinned to d036ad9781)
Solutions
- Save the original error code immediately after the failing Win32 call and use it instead of GET_LAST_ERROR() after intermediate calls.
- Log the numeric error code and look it up manually (net helpmsg / errlook.exe).
- Check available memory; ensure malloc(bufSize) succeeded before conversion.
- Retry the failing Windows API to re-capture a convertible error message.
Example fix
// before
int result = WideCharToMultiByte(...);
if (result == 0) { fprintf(stderr, "... %d\n", (int)GET_LAST_ERROR()); }
// after
DWORD originalErr = err; // captured right after the failing API
if (result == 0) { fprintf(stderr, "fmt failed (orig=%lu, conv=%d)\n", originalErr, (int)GET_LAST_ERROR()); } Defensive patterns
Strategy: validation
Validate before calling
// Capture and check the OS error code immediately after the failing Windows API
DWORD err = GetLastError();
if (err != 0) { /* record err now, before any malloc/LocalFree clobbers it */ } Prevention
- Capture GetLastError() before any intervening API calls
- Check malloc return before WideCharToMultiByte
- Log numeric Win32 error codes and decode with errlook.exe
- Test error-path formatting on all target locales
When it happens
Trigger: WideCharToMultiByte returns 0 while formatting a Win32 error message — e.g. malloc'd bufSize mismatch, invalid characters for CP_UTF8, or the GetLastError value being clobbered by intermediate calls (malloc/LocalFree) before reading it.
Common situations: Reporting obscure Win32 error codes (rare locale-specific messages), memory pressure making malloc fail, GetLastError already reset by an intervening API call so conversion reports a spurious error.
Related errors
- 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 ExpandEnvironm
- Win32Exception from native GetLastError after ExpandEnvironm
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/11a132d07d7111a5.
Report an issue: GitHub.