wailsapp/wails · error
Invoke SysFreeString error.
Error message
Invoke SysFreeString error.
What it means
The wrapper around SysFreeString panicked on a non-zero return. Like VariantInit, SysFreeString is declared void in oleaut32 — it returns no HRESULT — so this check reads an undefined register. A genuine failure mode is passing a BSTR pointer that is nil, already freed, or not allocated by SysAllocString, which corrupts the heap or trips allocator checks.
Source
Thrown at v3/pkg/w32/oleaut32.go:42
func VariantInit(v *VARIANT) {
hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
panic("Invoke VariantInit error.")
}
return
}
func SysAllocString(v string) (ss *int16) {
pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
ss = (*int16)(unsafe.Pointer(pss))
return
}
func SysFreeString(v *int16) {
hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
if hr != 0 {
panic("Invoke SysFreeString error.")
}
return
}
func SysStringLen(v *int16) uint {
l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
return uint(l)
}
View on GitHub (pinned to 0e754b1b40)
Solutions
- Free each BSTR exactly once; once a VT_BSTR VARIANT is passed to ComInvoke or cleared with VariantClear, do not also SysFreeString it
- Never pass pointers from StringToUTF16Ptr to SysFreeString — only SysAllocString results
- Patch the wrapper to ignore the (undefined) return value; report upstream
- Recover around COM cleanup blocks so a double-free panic is logged, not fatal
Example fix
// before
w32.SysFreeString(bstr) // panic if bstr already freed or not a BSTR
// after
type BSTR = *int16 // track ownership explicitly
freeBSTR := func(b *BSTR) {
if b == nil { return }
w32.SysFreeString(b)
*b = nil // idempotent second free
} Defensive patterns
Strategy: try-catch
Type guard
func isAllocatedBSTR(b *int16) bool {
return b != nil && w32.SysStringLen(b) >= 0 // crash on garbage anyway; ownership tracking is the real guard
} Try / catch
func freeBSTR(b *int16) {
defer func() { _ = recover() }() // log in real code
w32.SysFreeString(b)
} Prevention
- Track BSTR ownership explicitly; free exactly once
- After VariantClear or ComInvoke, treat the VARIANT's BSTR as gone
- Only free pointers returned by SysAllocString
When it happens
Trigger: Freeing the same *int16 BSTR twice; freeing a BSTR obtained from a VARIANT that was already VariantClear()ed; freeing a plain syscall.StringToUTF16Ptr result instead of a SysAllocString result.
Common situations: COM interop code that stores BSTRs in VARIANTs (VT_BSTR) and then manually frees them after the VARIANT was cleared; double-cleanup in error paths; porting code from go-ole where SysFreeString has no error return.
Related errors
- Invoke VariantInit error.
- ${await resp.text()}
- InvalidStateError
- ${await resp.text()}
- element has zero size (is it hidden?): ' + target.selector
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/f1d52e4d4be18095.
Report an issue: GitHub.