{"record":{"id":"78ea275c54096b30","repo":"wailsapp/wails","slug":"await-resp-text","errorCode":null,"errorMessage":"${await resp.text()}","messagePattern":"\\$\\{await resp\\.text\\(\\)\\}","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/internal/runtime/desktop/@wailsio/runtime/src/runtime.ts","lineNumber":212,"sourceCode":"async function sendChunked(url: URL, headers: Record<string, string>, bodyStr: string): Promise<Response> {\n    const chunkId = nanoid();\n    const bodyBytes = new TextEncoder().encode(bodyStr);\n    const totalChunks = Math.ceil(bodyBytes.length / CHUNK_THRESHOLD);\n\n    for (let i = 0; i < totalChunks - 1; i++) {\n        const chunk = bodyBytes.subarray(i * CHUNK_THRESHOLD, (i + 1) * CHUNK_THRESHOLD);\n        const resp = await fetch(url, {\n            method: 'POST',\n            headers: {\n                ...headers,\n                'x-wails-chunk-id': chunkId,\n                'x-wails-chunk-index': String(i),\n                'x-wails-chunk-total': String(totalChunks),\n            },\n            body: chunk,\n        });\n        if (!resp.ok) {\n            throw new Error(await resp.text());\n        }\n    }\n\n    return fetch(url, {\n        method: 'POST',\n        headers: {\n            ...headers,\n            'x-wails-chunk-id': chunkId,\n            'x-wails-chunk-index': String(totalChunks - 1),\n            'x-wails-chunk-total': String(totalChunks),\n        },\n        body: bodyBytes.subarray((totalChunks - 1) * CHUNK_THRESHOLD),\n    });\n}\n\n/**\n * Android WebView cannot deliver fetch() POST bodies to\n * shouldInterceptRequest, so the default HTTP transport cannot reach Go.","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v3/internal/runtime/desktop/@wailsio/runtime/src/runtime.ts#L194-L230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nh := w32.GlobalAlloc(w32.GMEM_MOVEABLE, uint32(len(data))) // 500MB clipboard blob -> panic\n\n// after\nconst maxClip = 100 << 20\nif len(data) > maxClip {\n\treturn fmt.Errorf(\"payload too large for clipboard: %d bytes\", len(data))\n}\nh := w32.GlobalAlloc(w32.GMEM_MOVEABLE, uint32(len(data)))\nif h == 0 {\n\treturn fmt.Errorf(\"GlobalAlloc failed for %d bytes\", len(data))\n}","handlingStrategy":"validation","validationCode":"const maxAlloc = 64 << 20\nfunc allocatable(size uint32) bool { return size > 0 && size <= maxAlloc }","typeGuard":null,"tryCatchPattern":"func safeGlobalAlloc(flags uint, size uint32) (h w32.HGLOBAL, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"GlobalAlloc(%d): %v\", size, r)\n\t\t}\n\t}()\n\treturn w32.GlobalAlloc(flags, size), nil\n}","preventionTips":["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."],"tags":["windows","memory","clipboard","syscall","panic"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}