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

  1. Open regedit or use Advapi32Util.registryGetValue / registryQueryInfoKey to check the value's actual type before reading.
  2. Call registryGetStringValue instead if the value is REG_SZ, or the matching getter for its actual type.
  3. Use registryGetValue, which dispatches on the reported type and returns an Object, when the type is not known in advance.
  4. 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

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


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