wailsapp/wails · error

unknown type

Error message

unknown type

What it means

ComInvoke converts variadic params into VARIANTs with a type switch covering int/int32, uint/uint32, int64, uint64, float32/64 (and pointers to each), string, *string, *IDispatch, **IDispatch, nil, and *VARIANT; anything else hits the default case and panics with 'unknown type'. It is a Marshaling limitation of this minimal wrapper, not a COM failure.

Source

Thrown at v3/pkg/w32/utils.go:198

				vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))}
			case float64:
				vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))}
			case *float64:
				vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))}
			case string:
				vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))}
			case *string:
				vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))}
			case *IDispatch:
				vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))}
			case **IDispatch:
				vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))}
			case nil:
				vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0}
			case *VARIANT:
				vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))}
			default:
				panic("unknown type")
			}
		}
		dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
		dispparams.CArgs = uint32(len(params))
	}

	var ret VARIANT
	var excepInfo EXCEPINFO
	VariantInit(&ret)
	hr, _, _ := syscall.SyscallN(disp.lpVtbl.pInvoke,
		uintptr(unsafe.Pointer(disp)),
		uintptr(dispid),
		uintptr(unsafe.Pointer(IID_NULL)),
		uintptr(GetUserDefaultLCID()),
		uintptr(dispatch),
		uintptr(unsafe.Pointer(&dispparams)),
		uintptr(unsafe.Pointer(&ret)),
		uintptr(unsafe.Pointer(&excepInfo)),

View on GitHub (pinned to 0e754b1b40)

Solutions

  1. Convert bools before the call — e.g. pass int32(-1)/int32(0) for VARIANT_TRUE/FALSE, or add a bool case mapping to VT_BOOL in the wrapper
  2. Narrow custom typed ints/floats to the built-in types (int32(weekDay), float64(ratio)) before calling
  3. For complex values, build a *w32.VARIANT yourself and pass that (VT_VARIANT|VT_BYREF is supported)
  4. Extend the switch upstream with the missing cases and contribute the patch

Example fix

// before
w32.ComInvoke(disp, dispid, w32.DISPATCH_METHOD, true) // bool -> panic

// after
variantTrue := int32(-1) // VARIANT_TRUE
w32.ComInvoke(disp, dispid, w32.DISPATCH_METHOD, variantTrue)
Defensive patterns

Strategy: type-guard

Type guard

func isSupportedVariantParam(v any) bool {
    switch v.(type) {
    case int, int32, uint, uint32, int64, uint64,
        float32, float64, string, *string,
        *w32.IDispatch, **w32.IDispatch, *w32.VARIANT, nil:
        return true
    case int8, uint8, int16, uint16, bool, []byte, time.Time:
        return false
    }
    return false
}

Prevention

When it happens

Trigger: Passing bool, int8/uint8, int16/uint16 (non-pointer), []byte, time.Time, structs, or any custom type as a parameter to w32.ComInvoke/ComPutProperty; passing a nil-valued interface with a concrete non-nil type.

Common situations: Automating COM APIs whose documented parameters are booleans (VT_BOOL) — the wrapper has no bool case, so even correct-looking code panics; passing Go strings wrapped in custom string types; sending enums represented as custom int types.

Related errors


AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15). Data as JSON: /api/errors/0da839cd7ffae17e. Report an issue: GitHub.