wailsapp/wails · error · Error
${await resp.text()}
Error message
${await resp.text()} What it means
GlobalAlloc allocates memory from the heap and returns an HGLOBAL handle; NULL means allocation failed. The w32 wrapper panics with 'GlobalAlloc failed' on NULL. With GMEM_MOVEABLE the call allocates a handle plus block; with GMEM_FIXED the handle is a direct pointer. Failure means out-of-memory or, rarely, invalid flags combinations such as requesting GMEM_FIXED together with GMEM_DISCARDABLE.
Source
Thrown at v3/internal/runtime/desktop/@wailsio/runtime/src/runtime.ts:212
async function sendChunked(url: URL, headers: Record<string, string>, bodyStr: string): Promise<Response> {
const chunkId = nanoid();
const bodyBytes = new TextEncoder().encode(bodyStr);
const totalChunks = Math.ceil(bodyBytes.length / CHUNK_THRESHOLD);
for (let i = 0; i < totalChunks - 1; i++) {
const chunk = bodyBytes.subarray(i * CHUNK_THRESHOLD, (i + 1) * CHUNK_THRESHOLD);
const resp = await fetch(url, {
method: 'POST',
headers: {
...headers,
'x-wails-chunk-id': chunkId,
'x-wails-chunk-index': String(i),
'x-wails-chunk-total': String(totalChunks),
},
body: chunk,
});
if (!resp.ok) {
throw new Error(await resp.text());
}
}
return fetch(url, {
method: 'POST',
headers: {
...headers,
'x-wails-chunk-id': chunkId,
'x-wails-chunk-index': String(totalChunks - 1),
'x-wails-chunk-total': String(totalChunks),
},
body: bodyBytes.subarray((totalChunks - 1) * CHUNK_THRESHOLD),
});
}
/**
* Android WebView cannot deliver fetch() POST bodies to
* shouldInterceptRequest, so the default HTTP transport cannot reach Go.View on GitHub (pinned to 0e754b1b40)
Solutions
- Check process memory usage at failure time; if the requested dwBytes is huge, stream the data in chunks instead of one allocation.
- Audit for missing GlobalFree on earlier allocations — pair every successful GlobalAlloc with a free via defer.
- Validate flags: use GMEM_MOVEABLE for clipboard/HGLOBAL consumers, GMEM_FIXED only when a raw pointer is fine; never mix GMEM_FIXED with discardable flags.
- On 32-bit builds, move to 64-bit or reduce payload size if the request itself exceeds address space.
- Wrap the allocation in a recover() guard if a graceful degradation (e.g. cancel the copy) is preferable to a crash.
Example fix
// before
h := w32.GlobalAlloc(w32.GMEM_MOVEABLE, uint32(len(data))) // 500MB clipboard blob -> panic
// after
const maxClip = 100 << 20
if len(data) > maxClip {
return fmt.Errorf("payload too large for clipboard: %d bytes", len(data))
}
h := w32.GlobalAlloc(w32.GMEM_MOVEABLE, uint32(len(data)))
if h == 0 {
return fmt.Errorf("GlobalAlloc failed for %d bytes", len(data))
} Defensive patterns
Strategy: validation
Validate before calling
const maxAlloc = 64 << 20
func allocatable(size uint32) bool { return size > 0 && size <= maxAlloc } Try / catch
func safeGlobalAlloc(flags uint, size uint32) (h w32.HGLOBAL, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("GlobalAlloc(%d): %v", size, r)
}
}()
return w32.GlobalAlloc(flags, size), nil
} Prevention
- Cap allocation sizes for clipboard/stream payloads and chunk larger data.
- Pair every GlobalAlloc with a deferred GlobalFree.
- Watch process commit charge when handling large payloads.
When it happens
Trigger: Allocating a buffer for clipboard data (SetClipboardData) or a stream (CreateStreamOnHGlobal) sized in the hundreds of MB on a memory-constrained machine; passing a bogus flag combination; running under a 32-bit process near the 2GB ceiling.
Common situations: Clipboard copy features that stage large images/text; a custom file-dialog or drag-drop data path serializing big payloads into HGLOBAL; a leak of prior GlobalAlloc blocks (missing GlobalFree) driving the process toward the commit limit so the next allocation panics.
Related errors
- ${await resp.text()}
- InvalidStateError
- Invalid JSON passed to callback: ${e.message}. Message: ${in
- Callback '${callbackID}' not registered!!!
- Invalid JSON passed to Notify: ${notifyMessage}
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/78ea275c54096b30.
Report an issue: GitHub.