{"record":{"id":"2062bfbd47d4f9df","repo":"jackwener/OpenCLI","slug":"discord-search-returned-malformed-browser-payload","errorCode":null,"errorMessage":"Discord search returned malformed browser payload.","messagePattern":"Discord search returned malformed browser payload\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/discord-app/search.js","lineNumber":54,"sourceCode":"        const resultNodes = document.querySelectorAll('[class*=\"searchResult_\"], [id*=\"search-result\"]');\n        \n        resultNodes.forEach((node, i) => {\n          const author = node.querySelector('[class*=\"username\"]')?.textContent?.trim() || '—';\n          const content = node.querySelector('[id^=\"message-content-\"], [class*=\"messageContent\"]')?.textContent?.trim() || node.textContent?.trim();\n          items.push({\n            Index: i + 1,\n            Author: author,\n            Message: (content || '').substring(0, 200),\n          });\n        });\n        \n        const bodyText = document.body?.innerText || document.body?.textContent || '';\n        const empty = /no results|no messages match|没有结果|无结果/i.test(bodyText);\n        return { items, empty };\n      })()\n    `);\n        if (!searchState || !Array.isArray(searchState.items)) {\n            throw new CommandExecutionError('Discord search returned malformed browser payload.');\n        }\n        const results = searchState.items;\n        // Close search\n        await page.pressKey('Escape');\n        if (results.length === 0) {\n            if (!searchState.empty) {\n                throw new CommandExecutionError('Discord search result selector returned no rows and no explicit empty-state marker.');\n            }\n            throw new EmptyResultError('discord-app search', `No results for \"${query}\".`);\n        }\n        return results;\n    },\n});\n","sourceCodeStart":36,"sourceCodeEnd":68,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/discord-app/search.js#L36-L68","documentation":"After running the search scrape script, the command expects searchState with an items array. If the injected script returned null/undefined or an object without an items array, it throws CommandExecutionError('Discord search returned malformed browser payload.'). This guards against the in-page scrape failing silently or returning an unexpected shape.","triggerScenarios":"The page.evaluate scrape script threw or returned undefined (page navigated mid-eval, context destroyed), the search results pane never rendered so the script bailed, or a Discord DOM change broke the script's return shape so items is missing.","commonSituations":"SPA re-render/unmount of the results panel during evaluation; evaluate called on a stale or closed frame; Discord update removing the container the script reads; heavy page making the script time out.","solutions":["Re-run the search command — a transient page re-render often resolves it.","Ensure the Discord tab/page is stable (no navigation, not minimized to the point scripts are throttled) during search.","Add/increase a wait after typing the query so results render before the scrape runs.","Update the scrape script to the current DOM if Discord changed the results container."],"exampleFix":"// before\nconst searchState = await page.evaluate(scrapeScript);\n// after: tolerate transient failure with a retry\nlet searchState = await page.evaluate(scrapeScript);\nif (!searchState) { await page.wait(1); searchState = await page.evaluate(scrapeScript); }","handlingStrategy":"retry","validationCode":"const ok = await page.evaluate(`!document.hidden && document.readyState === 'complete'`);\nif (!ok) await page.wait(1);","typeGuard":"function isWellFormedSearchState(s) { return s && Array.isArray(s.items) && typeof s.empty === 'boolean'; }","tryCatchPattern":"try {\n  await run('discord-app search --query=...');\n} catch (e) {\n  if (/malformed browser payload/.test(e.message)) {\n    await page.wait(1.5); // let SPA settle\n    await run('discord-app search --query=...');\n  }\n}","preventionTips":["Avoid navigating or switching channels while a search scrape is in flight.","Add a settle wait between typing the query and scraping results.","Keep the tab visible/active — background throttling can break evaluate timing.","Re-validate scrape script shape after Discord UI updates."],"tags":["discord","payload","browser-automation","scraping"],"backgroundTag":"malformed-response-payload","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}