{"record":{"id":"1566ba50253e20c5","repo":"jackwener/OpenCLI","slug":"failed-to-perform-action","errorCode":null,"errorMessage":"Failed to perform action.","messagePattern":"Failed to perform action\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/codex/_actions.js","lineNumber":221,"sourceCode":"    // action triggers a re-render that could swallow our reply.\n    const matchedLabel = leadingText(target);\n    Promise.resolve().then(() => { try { target.click(); } catch {} });\n    return { ok: true, clicked: matchedLabel };\n  })()`));\n\n    return result || { ok: false, reason: 'Empty result from page.evaluate.' };\n}\n\n/**\n * Convenience wrapper that selects the target first, then clicks the menu.\n */\nexport async function selectAndClickAction(page, kwargs, labelOptions) {\n    const selected = await resolveActionConversation(page, kwargs);\n    await page.wait(0.4);\n    const result = await clickChatActionsMenuItem(page, labelOptions);\n    if (!result.ok) {\n        const detail = result.detail ? ` ${result.detail}` : '';\n        throw new CommandExecutionError(\n            `${result.reason || 'Failed to perform action.'}${detail}`,\n            'Make sure Codex Desktop is running and the target conversation is selectable.',\n        );\n    }\n    return { ...result, selected };\n}\n\nexport async function waitForConversationPostcondition(page, ref, predicate, description, timeoutMs = 4000) {\n    const deadline = Date.now() + timeoutMs;\n    let lastMatch = null;\n    while (Date.now() < deadline) {\n        const projects = await readConversationProjects(page);\n        lastMatch = findCodexConversation(projects, ref);\n        if (predicate(lastMatch)) {\n            return lastMatch;\n        }\n        await page.wait(0.2);\n    }","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/codex/_actions.js#L203-L239","documentation":"selectAndClickAction resolves a conversation, then clicks a chat actions menu item (e.g. rename, archive). If the click helper reports failure, it throws this CommandExecutionError prefixed with the underlying reason (if any) and a hint to verify Codex Desktop is running and the conversation is selectable.","triggerScenarios":"The actions menu item could not be found or clicked: Codex Desktop not running, menu did not open, the item label/selector changed, or the resolved conversation became unselectable between resolution and click.","commonSituations":"Automation racing the UI (clicking before the menu renders), Codex updated its context-menu structure, the target conversation was closed by the user mid-automation.","solutions":["Make sure Codex Desktop is running and the conversation is open/selectable, then retry","Update opencli so its menu-item selectors match the current Codex UI","Add a small delay/retry around the action so the menu has time to render","Check result.reason in verbose output to identify the specific click failure"],"exampleFix":"// before\nawait selectAndClickAction(page, kwargs, { label: 'Archive' }); // races menu render\n// after\nawait page.wait(0.5);\nawait selectAndClickAction(page, kwargs, { label: 'Archive' });","handlingStrategy":"retry","validationCode":"await page.waitForSelector('.chat-actions-menu, [role=menu]', { timeout: 5000 });\nconst selected = await resolveActionConversation(page, kwargs);\nif (!selected) throw new Error('No selectable conversation; is Codex Desktop running?');","typeGuard":"function isClickOk(result) {\n  return Boolean(result && result.ok === true);\n}","tryCatchPattern":"for (let attempt = 1; attempt <= 3; attempt++) {\n  try {\n    await selectAndClickAction(page, kwargs, { label: 'Archive' });\n    break;\n  } catch (e) {\n    if (attempt === 3 || !e.message.includes('Failed to perform action')) throw e;\n    await page.wait(1);\n  }\n}","preventionTips":["Ensure Codex Desktop is running and unlocked before automation","Wait for the actions menu to render before clicking","Retry transient failures with a short backoff","Keep opencli selectors in sync with the Codex version you run"],"tags":["browser-automation","ui-selector","click-failed"],"backgroundTag":"ui-action-click-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}