java-native-access/jna · error · Win32Exception
Win32Exception (error code from Native.getLastError after Fi
Error message
Win32Exception (error code from Native.getLastError after FindFirstUrlCacheEntry with buffer)
What it means
WininetUtil.getCache() throws this Win32Exception when FindFirstUrlCacheEntry is called WITH an allocated INTERNET_CACHE_ENTRY_INFO buffer (after the sizing call) and returns a null handle, meaning the second invocation itself failed. The exception carries Native.getLastError(), distinguishing it from the pre-buffer sizing failure. Typically this means the entry disappeared between calls or the previously reported buffer size was no longer valid.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/WininetUtil.java:79
// for every entry, we call the API twice:
// once to get the size into the IntByReference
// then again to get the actual item
cacheHandle = Wininet.INSTANCE.FindFirstUrlCacheEntry(null, null, size);
lastError = Native.getLastError();
// if there's nothing in the cache, we're done.
if (lastError == WinError.ERROR_NO_MORE_ITEMS) {
return cacheItems;
} else if (lastError != WinError.ERROR_SUCCESS && lastError != WinError.ERROR_INSUFFICIENT_BUFFER) {
throw new Win32Exception(lastError);
}
INTERNET_CACHE_ENTRY_INFO entry = new INTERNET_CACHE_ENTRY_INFO(size.getValue());
cacheHandle = Wininet.INSTANCE.FindFirstUrlCacheEntry(null, entry, size);
if (cacheHandle == null) {
throw new Win32Exception(Native.getLastError());
}
items.add(entry);
while (true) {
size = new IntByReference();
// for every entry, we call the API twice:
// once to get the size into the IntByReference
// then again to get the actual item
boolean result = Wininet.INSTANCE.FindNextUrlCacheEntry(cacheHandle, null, size);
if (!result) {
lastError = Native.getLastError();
if (lastError == WinError.ERROR_NO_MORE_ITEMS) {
break;
} else if (lastError != WinError.ERROR_SUCCESS && lastError != WinError.ERROR_INSUFFICIENT_BUFFER) {
throw new Win32Exception(lastError);View on GitHub (pinned to d036ad9781)
Solutions
- Retry getCache() — transient races between the sizing call and the buffered call are the usual cause
- Catch Win32Exception and treat as an empty/failed enumeration rather than a fatal error if cache data is optional
- Ensure enumeration runs in the same user session that owns the cache and that no concurrent cache purge is in progress
- If it persists, upgrade JNA / verify the INTERNET_CACHE_ENTRY_INFO structure size matches the WinINet version
Example fix
// before
List<INTERNET_CACHE_ENTRY_INFO> items = WininetUtil.getCache();
// after
List<INTERNET_CACHE_ENTRY_INFO> items;
try {
items = WininetUtil.getCache();
} catch (Win32Exception e) {
items = Collections.emptyList();
} Defensive patterns
Strategy: retry
Try / catch
try {
items = WininetUtil.getCache();
} catch (Win32Exception e) {
items = retryOrEmpty(); // retry once, then empty list
} Prevention
- Expect races: the cache can change between sizing and buffered calls
- Retry the full enumeration once on failure
- Avoid enumerating while other processes purge the cache
When it happens
Trigger: Calling WininetUtil.getCache() when, after allocating the buffer of the size reported by the first FindFirstUrlCacheEntry call, the buffered FindFirstUrlCacheEntry(null, entry, size) still returns null — cache was flushed concurrently, or the size call raced with cache changes.
Common situations: Concurrent modification of the browser cache while enumerating (another process deleting entries); very large cache entries exceeding the allocated size; transient WinINet errors under heavy load.
Related errors
- Win32Exception (error code from Native.getLastError after Fi
- Win32Exception (error code from Native.getLastError after Fi
- Win32Exception (error code from Native.getLastError after Fi
- Win32Exception from native GetLastError after ExpandEnvironm
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/7e92a70011a445b0.
Report an issue: GitHub.