{"record":{"id":"96708b4bcc780e2d","repo":"jackwener/OpenCLI","slug":"could-not-find-the-chatgpt-model-selector-in-the-c","errorCode":null,"errorMessage":"Could not find the ChatGPT model selector in the composer.","messagePattern":"Could not find the ChatGPT model selector in the composer\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chatgpt/utils.js","lineNumber":650,"sourceCode":"        let button = Array.from(document.querySelectorAll('form button')).find((node) =>\n            isVisible(node) && labels.some((label) => textMatchesLabel(node.textContent, label))\n        );\n        if (!button) {\n            button = menuButtonSelectors\n                .map((selector) => document.querySelector(selector))\n                .find((node) => node instanceof HTMLElement && isVisible(node));\n        }\n        if (!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 model menu button');\n    if (!menuButton.found) {\n        throw new CommandExecutionError('Could not find the ChatGPT model selector 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 escapeRegExp = (value) => String(value).replace(/[|\\\\\\\\{}()[\\\\]^$+*?.]/g, '\\\\\\\\$&');\n            const textMatchesLabel = (text, label) => {\n                const normalizedText = normalize(text);","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chatgpt/utils.js#L632-L668","documentation":"After ensuring the composer is visible, selectChatGPTModel evaluates a script to locate the model-selector button in the composer. If no matching element (by testid/aria-label/geometry) is found, menuButton.found stays false and the library throws CommandExecutionError. This guards against clicking at bogus coordinates.","triggerScenarios":"The model switcher button is absent from the composer DOM — typically a ChatGPT UI A/B variant or redesign, page not fully hydrated, locale rendering unexpected labels, the composer in a state where the selector is hidden (e.g. temporary chat, some compact layouts), or a CSP/environment blocking the evaluate script.","commonSituations":"ChatGPT frontend rollout changing data-testid of the model switcher; page checked too early before the composer toolbar renders; non-default ChatGPT modes (temporary chat, project canvases) that hide the model picker; layouts where the button rect is zero-sized.","solutions":["Retry after a short wait so the composer toolbar finishes rendering.","Set OPENCLI_CHATGPT_MODEL_DEBUG=1 to inspect how far the flow got and what the page URL/state was.","Open ChatGPT manually and confirm the model selector exists in your UI variant/locale; disable temporary-chat or special modes.","Update the opencli package so its selector list matches the current ChatGPT DOM.","If the API path applies to your target model, rely on setChatGPTModelConfig (API) rather than the picker fallback."],"exampleFix":"// before\nawait selectChatGPTModel(page, 'balanced'); // fails when UI not hydrated\n// after\nawait page.wait(2); // let composer toolbar render\nawait selectChatGPTModel(page, 'balanced');","handlingStrategy":"retry","validationCode":"await ensureChatGPTComposer(page);\nawait page.wait(1.5); // let the composer toolbar render before locating the selector button","typeGuard":"function menuButtonFound(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 selectChatGPTModel(page, model); }\n  catch (err) {\n    if (!(err instanceof CommandExecutionError) || !/model selector/.test(err.message)) throw err;\n    await page.wait(1.5);\n  }\n}\nthrow new Error('model selector never appeared');","preventionTips":["Wait for full page hydration before model selection.","Avoid temporary-chat/canvas modes that hide the model picker.","Track library updates for ChatGPT UI rollouts.","Use a UI language covered by the selector labels (English or Chinese)."],"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"}