java-native-access/jna · error · RuntimeException
Unexpected registry type + lpType.getValue() + , expected RE
Error message
Unexpected registry type + lpType.getValue() + , expected REG_SZ
What it means
Advapi32Util.registryGetExpandableStringValue first queries the registry value with RegQueryValueEx using a NULL buffer to learn the value's type via lpType. If the returned type is not WinNT.REG_EXPAND_SZ, the library throws this RuntimeException because the retrieved data would not be an expandable string. The message text itself is slightly misleading (says REG_SZ), but the check is against REG_EXPAND_SZ. It is a defensive guard so callers never receive wrongly-decoded data.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java:863
* Get a registry REG_EXPAND_SZ value.
*
* @param hKey
* Parent Key.
* @param value
* Name of the value to retrieve.
* @return String value.
*/
public static String registryGetExpandableStringValue(HKEY hKey, String value) {
IntByReference lpcbData = new IntByReference();
IntByReference lpType = new IntByReference();
int rc = Advapi32.INSTANCE.RegQueryValueEx(hKey, value, 0,
lpType, (char[]) null, lpcbData);
if (rc != W32Errors.ERROR_SUCCESS
&& rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
throw new Win32Exception(rc);
}
if (lpType.getValue() != WinNT.REG_EXPAND_SZ) {
throw new RuntimeException("Unexpected registry type "
+ lpType.getValue() + ", expected REG_SZ");
}
if (lpcbData.getValue() == 0) {
return "";
}
// See comment in #registryGetValue
Memory mem = new Memory(lpcbData.getValue() + Native.WCHAR_SIZE);
mem.clear();
rc = Advapi32.INSTANCE.RegQueryValueEx(hKey, value, 0,
lpType, mem, lpcbData);
if (rc != W32Errors.ERROR_SUCCESS
&& rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
throw new Win32Exception(rc);
}
if (W32APITypeMapper.DEFAULT == W32APITypeMapper.UNICODE) {
return mem.getWideString(0);
} else {
return mem.getString(0);View on GitHub (pinned to d036ad9781)
Solutions
- Open regedit or use Advapi32Util.registryGetValue / registryQueryInfoKey to check the value's actual type before reading.
- Call registryGetStringValue instead if the value is REG_SZ, or the matching getter for its actual type.
- Use registryGetValue, which dispatches on the reported type and returns an Object, when the type is not known in advance.
- Catch RuntimeException around the typed getter and fall back to a generic read.
Example fix
// before String v = Advapi32Util.registryGetExpandableStringValue(WinReg.HKEY_LOCAL_MACHINE, "SOFTWARE\\MyApp", "Path"); // after Object raw = Advapi32Util.registryGetValue(WinReg.HKEY_LOCAL_MACHINE, "SOFTWARE\\MyApp", "Path"); String v = raw instanceof String ? (String) raw : String.valueOf(raw);
Defensive patterns
Strategy: validation
Validate before calling
// check the value's type before the typed read
Advapi32Util.InfoKey info = Advapi32Util.registryQueryInfoKey(key, 0);
// or cheaper: read generically and instanceof-check
Object v = Advapi32Util.registryGetValue(root, keyPath, valueName);
if (!(v instanceof String)) throw new IllegalStateException("Expected expandable string"); Type guard
boolean isExpandableString(Object v) { return v instanceof String; } Try / catch
try { return Advapi32Util.registryGetExpandableStringValue(root, key, value); }
catch (RuntimeException e) { log.warn("Not REG_EXPAND_SZ: {}", value); return null; } Prevention
- Query the value type with registryQueryInfoKey before using a typed getter
- Prefer registryGetValue when the type is not guaranteed
- Never assume a value's type from its name or documentation alone
- Re-check types after installers or group policy may rewrite values
When it happens
Trigger: Calling Advapi32Util.registryGetExpandableStringValue(root, key, value) (or the samDesiredExtra overload) where the named registry value exists but has a type other than REG_EXPAND_SZ, e.g. it is REG_SZ, REG_DWORD or REG_BINARY.
Common situations: Reading a value that an installer or another application rewrote as a plain REG_SZ; guessing that a value is expandable when it was created with setValue returning REG_SZ; hardcoding value names from documentation that changed between Windows versions.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unexpected registry type {}, expected REG_SZ
- Unexpected registry type {}, expected REG_BINARY
- Unexpected registry type {}, expected REG_DWORD
- Unexpected registry type {}, expected REG_QWORD
- Unexpected registry type + lpType.getValue() + , expected RE
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/a9528fefe358ecbf.
Report an issue: GitHub.