wailsapp/wails · error · Error
Invalid JSON passed to Notify: ${notifyMessage}
Error message
Invalid JSON passed to Notify: ${notifyMessage} What it means
SelectObject wraps gdi32.SelectObject, which selects a GDI object (pen, brush, font, bitmap) into a device context and returns the previously selected object. The w32 wrapper panics with 'SelectObject failed' when the API returns NULL/0. Windows returns failure when the handle is not a valid GDI object, does not match a type the DC accepts, or has already been deleted — a classic use-after-delete bug. Note the wrapper's zero check is also technically lossy for regions, where the error return is HGDI_ERROR rather than NULL.
Source
Thrown at v2/internal/frontend/runtime/desktop/events.js:132
}
}
}
/**
* Notify informs frontend listeners that an event was emitted with the given data
*
* @export
* @param {string} notifyMessage - encoded notification message
*/
export function EventsNotify(notifyMessage) {
// Parse the message
let message;
try {
message = JSON.parse(notifyMessage);
} catch (e) {
const error = 'Invalid JSON passed to Notify: ' + notifyMessage;
throw new Error(error);
}
notifyListeners(message);
}
/**
* Emit an event with the given name and data
*
* @export
* @param {string} eventName
*/
export function EventsEmit(eventName) {
const payload = {
name: eventName,
data: [].slice.apply(arguments).slice(1),
};
// Notify JS listenersView on GitHub (pinned to 0e754b1b40)
Solutions
- Ensure the object being selected was created (CreateSolidBrush, CreateCompatibleBitmap, ...) and not deleted; search for DeleteObject calls on shared objects.
- Follow the save/restore idiom: store the return value (the old object) and re-select it before deleting your object and the DC.
- Never have one HBITMAP selected into two DCs simultaneously; create one compatible bitmap per DC.
- Confirm the object type matches what the DC expects at that slot (bitmap only into memory DCs).
- Run with Application Verifier or GDI diagnostic tools (e.g. GDIView) to find which handle is dead at selection time.
Example fix
// before old := w32.SelectObject(hdcMem, hbm) w32.DeleteObject(hbm) // still selected in another DC -> later SelectObject panics // after old := w32.SelectObject(hdcMem, hbm) defer w32.SelectObject(hdcMem, old) // restore first // ... draw ... w32.DeleteObject(hbm) // delete only after restore
Defensive patterns
Strategy: validation
Try / catch
func safeSelect(hdc w32.HDC, obj w32.HGDIOBJ) (old w32.HGDIOBJ, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("SelectObject: %v (object deleted or wrong type?)", r)
}
}()
return w32.SelectObject(hdc, obj), nil
} Prevention
- Always save the returned old object and re-select it before deleting your object or the DC.
- Delete a GDI object only when it is not selected into any DC.
- Never share one HBITMAP across two memory DCs at the same time.
When it happens
Trigger: Selecting a bitmap/pen/brush that was already passed to DeleteObject; selecting a bitmap into more than one memory DC at a time (GDI forbids this); passing a handle of the wrong type (e.g. an HBRUSH where an HBITMAP is required); using a DC after DeleteDC.
Common situations: Double-buffering code that deletes the old bitmap but keeps selecting it again on the next frame; cleanup routines that delete brushes still selected into a live DC; porting drawing code from C where the old object restore order was accidental but tolerated.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid JSON passed to callback: ${e.message}. Message: ${in
- Callback '${callbackID}' not registered!!!
- CancellablePromise does not support transparent subclassing.
- CancellablePromise.prototype.then called on an invalid objec
- CancellablePromise.prototype.finally called on an invalid ob
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/5f6728c323671d56.
Report an issue: GitHub.