{"record":{"id":"ad6ff42bc532e8aa","repo":"jackwener/OpenCLI","slug":"context-returned-malformed-browser-output","errorCode":null,"errorMessage":"${context} returned malformed browser output.","messagePattern":"(.+?) returned malformed browser output\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/discord-app/utils.js","lineNumber":21,"sourceCode":"const DISCORD_HOSTS = new Set(['discord.com', 'canary.discord.com', 'ptb.discord.com']);\nconst DISCORD_ORIGIN = 'https://discord.com';\nconst CHANNEL_ID_RE = /^\\d{3,}$/;\n\nfunction stringArg(value) {\n    return typeof value === 'string' && value.trim() ? value.trim() : '';\n}\n\nexport function unwrapEvaluateResult(payload) {\n    if (payload && typeof payload === 'object' && !Array.isArray(payload) && 'session' in payload && 'data' in payload) {\n        return payload.data;\n    }\n    return payload;\n}\n\nfunction requireObjectEvaluateResult(payload, context) {\n    const value = unwrapEvaluateResult(payload);\n    if (!value || typeof value !== 'object' || Array.isArray(value)) {\n        throw new CommandExecutionError(`${context} returned malformed browser output.`);\n    }\n    return value;\n}\n\nfunction requireArrayEvaluateResult(payload, context) {\n    const value = unwrapEvaluateResult(payload);\n    if (!Array.isArray(value)) {\n        throw new CommandExecutionError(`${context} returned malformed browser output.`);\n    }\n    return value;\n}\n\nfunction requireNonEmptyRowField(row, field, context, index) {\n    if (!row || typeof row !== 'object' || Array.isArray(row)) {\n        throw new CommandExecutionError(`${context} returned malformed row ${index + 1}.`);\n    }\n    const value = String(row[field] || '').trim();\n    if (!value) {","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/discord-app/utils.js#L3-L39","documentation":"requireObjectEvaluateResult unwraps the result of an in-page browser evaluate call and asserts it is a plain (non-array) object. If the payload is null, an array, or a primitive, it throws CommandExecutionError with '<context> returned malformed browser output.' It is raised by state, waitForDiscordRoute and waitForDiscordContent when the route-state script returns an unexpected shape.","triggerScenarios":"The in-page evaluate that reads Discord route state returns null/undefined (script threw inside the page), an array, or a string instead of an object — e.g. the page navigated mid-evaluate, the evaluation was serialized unexpectedly, or the route-state script was updated to return a non-object.","commonSituations":"Discord navigating/reloading while waitForDiscordRoute polls, causing the evaluate to resolve with null; a browser automation driver returning a wrapped or serialized payload the unwrapEvaluateResult doesn't recognize; a modified buildRouteStateScript accidentally returning a string.","solutions":["Re-run the command; transient navigation during polling often resolves it","Inspect the automation driver's evaluate return handling to ensure plain objects are returned unserialized","Confirm buildRouteStateScript still returns an object after any Discord UI/automation updates","Wrap waitForDiscordRoute/waitForDiscordContent polling calls to tolerate and retry a malformed payload before failing"],"exampleFix":"// before\nconst state = await page.evaluate(buildRouteStateScript());\n// after (tolerate transient malformed results)\nlet state = null;\nfor (let i = 0; i < 3 && !state; i++) {\n  try { state = requireObjectEvaluateResult(await page.evaluate(buildRouteStateScript()), 'state'); }\n  catch { await page.waitForTimeout(500); }\n}","handlingStrategy":"retry","validationCode":"async function safeRouteState(page) {\n  const payload = await page.evaluate(buildRouteStateScript());\n  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return null;\n  return payload;\n}","typeGuard":"function isRouteState(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  await waitForDiscordRoute(page, target);\n} catch (err) {\n  if (String(err.message).includes('malformed browser output')) {\n    await page.waitForTimeout(1000);\n    await waitForDiscordRoute(page, target); // transient navigation; retry once\n  } else throw err;\n}","preventionTips":["Avoid triggering navigation/reloads while polling route state","Keep the automated page on a discord.com origin during waits","Confirm buildRouteStateScript still returns a plain object after updates","Retry polling once on malformed output before failing"],"tags":["discord","browser-automation","contract-violation"],"backgroundTag":"malformed-browser-output","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}