{"record":{"id":"5c9206e20f992e2e","repo":"jackwener/OpenCLI","slug":"codex-sidebar-extraction-returned-an-invalid-paylo","errorCode":null,"errorMessage":"Codex sidebar extraction returned an invalid payload.","messagePattern":"Codex sidebar extraction returned an invalid payload\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/codex/_actions.js","lineNumber":86,"sourceCode":"    return null;\n}\n\nexport function findActiveCodexConversation(projects) {\n    const active = [];\n    for (const project of projects || []) {\n        for (const conversation of project.conversations || []) {\n            if (conversation.active) {\n                active.push({ project, conversation });\n            }\n        }\n    }\n    return active.length === 1 ? active[0] : null;\n}\n\nexport async function readConversationProjects(page) {\n    const projects = unwrapEvaluateResult(await page.evaluate(`(${collectCodexProjectsFromDocument.toString()})()`));\n    if (!Array.isArray(projects)) {\n        throw new CommandExecutionError('Codex sidebar extraction returned an invalid payload.');\n    }\n    return projects;\n}\n\nexport async function resolveActionConversation(page, kwargs) {\n    const selected = await openCodexConversation(page, kwargs);\n    const projects = await readConversationProjects(page);\n    const resolved = selected\n        ? findCodexConversation(projects, selected)\n        : findActiveCodexConversation(projects);\n    if (!resolved) {\n        const hint = hasConversationTarget(kwargs)\n            ? 'The selected Codex conversation was not visible after selection.'\n            : 'Pass --project/--conversation/--index/--thread-id, or keep the active conversation visible in the sidebar.';\n        throw new CommandExecutionError('Could not resolve a stable Codex conversation identity.', hint);\n    }\n    if (!resolved.conversation.threadId) {\n        throw new CommandExecutionError(","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/codex/_actions.js#L68-L104","documentation":"readConversationProjects runs an in-page script (collectCodexProjectsFromDocument) in the Codex web UI to extract the conversation sidebar rows, unwrapping the evaluate result. If the result is not an array the DOM extraction contract is broken, so opencli throws this CommandExecutionError instead of operating on bad data.","triggerScenarios":"page.evaluate returns null/undefined/non-array because the sidebar is absent, the page is still loading, the user is logged out, or collectCodexProjectsFromDocument's selectors no longer match after a Codex UI change.","commonSituations":"Codex Desktop not running / page on an error or login screen, sidebar collapsed or empty, Codex deployed a DOM redesign that breaks the extraction script.","solutions":["Confirm Codex Desktop is running and the app page is fully loaded with the sidebar visible","Log in / re-establish the session if the page shows a login screen","Update opencli so its extraction selectors match the current Codex UI","Retry after the page finishes loading"],"exampleFix":"// before\nconst projects = await readConversationProjects(page); // throws if page still loading\n// after\nawait page.waitForSelector('[data-sidebar]', { timeout: 10000 });\nconst projects = await readConversationProjects(page);","handlingStrategy":"type-guard","validationCode":"await page.waitForSelector('.sidebar', { timeout: 10000 });\nconst projects = unwrapEvaluateResult(\n  await page.evaluate(`(${collectCodexProjectsFromDocument.toString()})()`)\n);\nif (!Array.isArray(projects)) throw new Error('Sidebar not ready; aborting');","typeGuard":"function isProjectArray(v) {\n  return Array.isArray(v) && v.every(p => p && typeof p.project === 'string' && Array.isArray(p.conversations));\n}","tryCatchPattern":"try {\n  const projects = await readConversationProjects(page);\n} catch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('invalid payload')) {\n    await page.reload();\n    await page.waitForSelector('.sidebar');\n    // retry once\n  } else throw e;\n}","preventionTips":["Wait for the sidebar to render before extraction","Verify the Codex session is authenticated before automating","Pin/track opencli versions against known Codex UI builds","Log the raw evaluate result when extraction fails"],"tags":["browser-automation","ui-selector","dom-extraction"],"backgroundTag":"dom-extraction-invalid-payload","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}