{"record":{"id":"3d10cfb0c4499d99","repo":"jackwener/OpenCLI","slug":"could-not-find-the-chatgpt-tools-menu-button-in-th","errorCode":null,"errorMessage":"Could not find the ChatGPT tools menu button in the composer.","messagePattern":"Could not find the ChatGPT tools menu button in the composer\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chatgpt/utils.js","lineNumber":854,"sourceCode":"        const isVisible = (el) => {\n            if (!(el instanceof HTMLElement)) return false;\n            const style = window.getComputedStyle(el);\n            if (style.display === 'none' || style.visibility === 'hidden') return false;\n            const rect = el.getBoundingClientRect();\n            return rect.width > 0 && rect.height > 0;\n        };\n        const button = document.querySelector('button[data-testid=\"composer-plus-btn\"]');\n        if (!(button instanceof HTMLElement) || !isVisible(button)) return { found: false };\n        button.scrollIntoView({ block: 'center', inline: 'center' });\n        const rect = button.getBoundingClientRect();\n        return {\n            found: true,\n            x: Math.round(rect.left + rect.width / 2),\n            y: Math.round(rect.top + rect.height / 2),\n        };\n    })()`)), 'chatgpt tools menu button');\n    if (!menuButton.found) {\n        throw new CommandExecutionError('Could not find the ChatGPT tools menu button in the composer.');\n    }\n    await page.nativeClick(Number(menuButton.x), Number(menuButton.y));\n    await page.wait(0.5);\n\n    let optionCenter = null;\n    for (let attempt = 0; attempt < 10; attempt += 1) {\n        optionCenter = requireObjectEvaluateResult(unwrapEvaluateResult(await page.evaluate(`(() => {\n            const isVisible = (el) => {\n                if (!(el instanceof HTMLElement)) return false;\n                const style = window.getComputedStyle(el);\n                if (style.display === 'none' || style.visibility === 'hidden') return false;\n                const rect = el.getBoundingClientRect();\n                return rect.width > 0 && rect.height > 0;\n            };\n            const normalize = (value) => String(value || '').replace(/\\\\s+/g, ' ').trim();\n            const compact = (value) => normalize(value).toLowerCase().replace(/[^\\\\p{L}\\\\p{N}]+/gu, '');\n            const labels = ${JSON.stringify(target.labels)};\n            const optionSelector = '[role=\"menuitemradio\"], [role=\"menuitem\"], [role=\"option\"], button, div[tabindex=\"0\"]';","sourceCodeStart":836,"sourceCodeEnd":872,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chatgpt/utils.js#L836-L872","documentation":"selectChatGPTTool evaluates a script to find the tools-menu button in the composer; if no element matches, menuButton.found is false and it throws CommandExecutionError. Like the model-selector case, this exists to avoid clicking invalid coordinates when the expected control is missing from the DOM.","triggerScenarios":"The tools menu button (\"+\" actions button) is not present in the composer — ChatGPT UI variant/redesign, page not hydrated yet, locale/labels mismatch, special composer states (canvas, voice mode, some workspaces) hiding the tools button, or the evaluate script being blocked/returning unexpected shapes.","commonSituations":"New ChatGPT layouts that relocate or rename the tools button; automation running before the composer toolbar renders; UI language not covered by the labels list; temporary chat or feature-flagged variants where the tools menu is absent.","solutions":["Retry after a brief wait so the composer toolbar finishes rendering.","Open ChatGPT manually and confirm the tools (\"+\") button exists in your UI variant/locale; exit special modes like canvas/voice.","Set OPENCLI_CHATGPT_MODEL_DEBUG=1 to trace the failing step.","Update the opencli package so its selectors match the current ChatGPT DOM."],"exampleFix":"// before\nawait selectChatGPTTool(page, 'deep-research'); // tools button not yet rendered\n// after\nawait page.wait(2);\nawait selectChatGPTTool(page, 'deep-research');","handlingStrategy":"retry","validationCode":"await ensureChatGPTComposer(page);\nawait page.wait(1.5); // let composer toolbar (with the \"+\" tools button) render","typeGuard":"function toolsButtonFound(res) {\n  return res != null && res.found === true && Number.isFinite(Number(res.x)) && Number.isFinite(Number(res.y));\n}","tryCatchPattern":"for (let i = 0; i < 3; i++) {\n  try { return await selectChatGPTTool(page, tool); }\n  catch (err) {\n    if (!(err instanceof CommandExecutionError) || !/tools menu button/.test(err.message)) throw err;\n    await page.wait(1.5);\n  }\n}\nthrow new Error('tools menu button never appeared');","preventionTips":["Wait for composer hydration before tool selection.","Exit canvas/voice/temporary-chat modes that hide the tools button.","Keep the UI language within the supported label set.","Track library updates for ChatGPT toolbar DOM changes."],"tags":["browser-automation","dom-selector","chatgpt","ui-change"],"backgroundTag":"dom-element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}