java-native-access/jna · error · RuntimeException
Unexpected registry type + lpType.getValue() + , expected RE
Error message
Unexpected registry type + lpType.getValue() + , expected REG_SZ or REG_EXPAND_SZ
What it means
A plain java.lang.RuntimeException thrown when the queried registry value's declared type is neither REG_SZ nor REG_EXPAND_SZ. registryGetStringValue only handles string values; a REG_DWORD, REG_BINARY, REG_MULTI_SZ, etc. value is rejected with this message (whose concatenation lists the numeric type code). Note the code builds the message via string concatenation, so the raw numeric type (e.g. 4 for REG_DWORD) appears in the text.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java:773
*
* @param hKey
* Parent Key.
* @param value
* Name of the value to retrieve.
* @return String value.
*/
public static String registryGetStringValue(HKEY hKey, String value) {
IntByReference lpcbData = new IntByReference();
IntByReference lpType = new IntByReference();
int rc = Advapi32.INSTANCE.RegQueryValueEx(hKey, value, 0,
lpType, (Pointer) null, lpcbData);
if (rc != W32Errors.ERROR_SUCCESS
&& rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
throw new Win32Exception(rc);
}
if (lpType.getValue() != WinNT.REG_SZ
&& lpType.getValue() != WinNT.REG_EXPAND_SZ) {
throw new RuntimeException("Unexpected registry type "
+ lpType.getValue()
+ ", expected REG_SZ or REG_EXPAND_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 {View on GitHub (pinned to d036ad9781)
Solutions
- Use the type-appropriate getter: registryGetIntValue for REG_DWORD, registryGetBinaryValue for REG_BINARY, registryGetStringArray for REG_MULTI_SZ.
- Inspect the type first via Advapi32Util.registryGetValue/registryQueryValue and dispatch on it.
- Recreate the value as a REG_SZ if you own it (reg add /t REG_SZ or PowerShell Set-ItemProperty).
- Catch RuntimeException from this call and fall back to a generic read + manual conversion.
- Check whether the 32/64-bit view you query contains a differently typed value than expected (KEY_WOW64 flags).
Example fix
// before String v = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, key, "Timeout"); // Timeout is REG_DWORD // after Object raw = Advapi32Util.registryGetValue(WinReg.HKEY_LOCAL_MACHINE, key, "Timeout"); String v = (raw instanceof String) ? (String) raw : String.valueOf(raw);
Defensive patterns
Strategy: validation
Validate before calling
// inspect the value type before choosing a getter
Object raw = Advapi32Util.registryGetValue(root, key, value);
if (raw != null && !(raw instanceof String)) {
throw new IllegalStateException("Value " + value + " is not REG_SZ (type=" + raw.getClass().getSimpleName() + ")");
} Type guard
static boolean isStringRegistryValue(HKEY root, String key, String value) {
Object v = Advapi32Util.registryGetValue(root, key, value);
return v instanceof String;
} Try / catch
try {
return Advapi32Util.registryGetStringValue(hKey, value);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("Unexpected registry type")) {
return String.valueOf(Advapi32Util.registryGetValue(hKey, value)); // fallback conversion
}
throw e;
} Prevention
- Use registryGetValue to discover the type, then pick the typed getter.
- Never assume all values under a key are strings - installers store DWORDs/binary freely.
- For REG_MULTI_SZ use registryGetStringArray; REG_DWORD use registryGetIntValue.
- Watch for type changes across application versions/group policy.
- Use KEY_WOW64 flags to be sure you read the same view the value was written to.
When it happens
Trigger: Calling Advapi32Util.registryGetStringValue(root/hKey, ..., value) on a value stored as REG_DWORD (4), REG_BINARY (3), REG_MULTI_SZ (7), REG_QWORD (11) or any type other than 1 (REG_SZ) / 2 (REG_EXPAND_SZ); RegQueryValueEx succeeds but lpType.getValue() fails the type check.
Common situations: Registry value type changed by an installer or group policy between app versions; assuming all values under a key are strings; reading a DWORD 'flags' value with the string getter; migrating code from a generic registryGetValue call to the string-specific one.
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
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
- Expected GetTokenInformation to fail with ERROR_INSUFFICIENT
- Unexpected registry type + lpType.getValue() + , expected RE
- Unexpected registry type {}, expected REG_SZ
- Unexpected registry type {}, expected REG_BINARY
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/1dc66fbaa7f944a3.
Report an issue: GitHub.