wailsapp/wails · error
SendMessage(LVM_SETCALLBACKMASK)
Error message
SendMessage(LVM_SETCALLBACKMASK)
What it means
ListView's checkbox support (SetCheckBoxes -> the setCheckboxMask helper) reads the current callback mask with LVM_GETCALLBACKMASK, sets/clears LVIS_STATEIMAGEMASK, then sends LVM_SETCALLBACKMASK and panics if the message returns FALSE. The message fails when the HWND is not a list-view in a valid state — typically a destroyed window or a handle that never was a SysListView32 — because a live list-view accepts any callback mask.
Source
Thrown at v2/internal/frontend/desktop/windows/winc/listview.go:207
oldStyle := exStyle
if value {
exStyle |= w32.LVS_EX_CHECKBOXES
} else {
exStyle &^= w32.LVS_EX_CHECKBOXES
}
if exStyle != oldStyle {
w32.SendMessage(lv.hwnd, w32.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)
}
mask := w32.SendMessage(lv.hwnd, w32.LVM_GETCALLBACKMASK, 0, 0)
if value {
mask |= w32.LVIS_STATEIMAGEMASK
} else {
mask &^= w32.LVIS_STATEIMAGEMASK
}
if w32.SendMessage(lv.hwnd, w32.LVM_SETCALLBACKMASK, mask, 0) == w32.FALSE {
panic("SendMessage(LVM_SETCALLBACKMASK)")
}
}
func (lv *ListView) applyImage(lc *w32.LVITEM, imIndex int) {
if lv.iml != nil {
lc.Mask |= w32.LVIF_IMAGE
lc.IImage = int32(imIndex)
}
}
func (lv *ListView) AddItem(item ListItem) {
lv.InsertItem(item, lv.ItemCount())
}
func (lv *ListView) InsertItem(item ListItem, index int) {
text := item.Text()
li := &w32.LVITEM{
Mask: w32.LVIF_TEXT | w32.LVIF_PARAM,View on GitHub (pinned to 0e754b1b40)
Solutions
- Configure checkboxes once at setup, on the UI thread, while the form is guaranteed alive
- Guard late/async calls with w32.IsWindow(lv.Handle()) before SetCheckBoxes
- Cancel pending UI-mutating goroutines when the form closes (context/WaitGroup tied to WM_DESTROY)
Example fix
// before
func (f *MainForm) onSettingsChange() {
f.list.SetCheckBoxes(true) // may run after window destroyed -> LVM_SETCALLBACKMASK FALSE -> panic
}
// after
func (f *MainForm) onSettingsChange() {
if !w32.IsWindow(f.list.Handle()) { return }
f.list.SetCheckBoxes(true)
} Defensive patterns
Strategy: validation
Validate before calling
func setCheckBoxesSafe(lv *winc.ListView, on bool) {
if lv == nil || lv.Handle() == 0 || !w32.IsWindow(lv.Handle()) { return }
lv.SetCheckBoxes(on)
} Prevention
- Configure checkboxes once at control setup on the UI thread
- Stop configuration goroutines when the form closes
When it happens
Trigger: Calling listView.SetCheckBoxes(true) after the control's window was destroyed; calling it from a goroutine racing form teardown; invoking it on a control whose creation failed so hwnd is 0; sending LVM_* to a non-listview handle via misuse of the API.
Common situations: App shutdown paths that reconfigure UI (e.g. persisting preferences triggers SetCheckBoxes) while the window is closing; deferred configuration callbacks firing after close.
Related errors
- SendMessage(LVM_UPDATE)
- GetSysColorBrush failed
- cannot create window for " + className
- failed CreateMenu
- failed SetMenu
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/bd3ed7b8164947dc.
Report an issue: GitHub.