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

  1. Retry getCache() — transient races between the sizing call and the buffered call are the usual cause
  2. Catch Win32Exception and treat as an empty/failed enumeration rather than a fatal error if cache data is optional
  3. Ensure enumeration runs in the same user session that owns the cache and that no concurrent cache purge is in progress
  4. 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

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


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/7e92a70011a445b0. Report an issue: GitHub.