{"record":{"id":"7e6344901f30ad65","repo":"jackwener/OpenCLI","slug":"result-reason-7e6344","errorCode":null,"errorMessage":"${result.reason}","messagePattern":"\\$\\{result\\.reason\\}","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/codex/model.js","lineNumber":225,"sourceCode":"      const cinit = {\n        bubbles: true, cancelable: true, button: 0, buttons: 1,\n        clientX: Math.round(cr.left + cr.width / 2),\n        clientY: Math.round(cr.top + cr.height / 2),\n      };\n      Promise.resolve().then(() => {\n        try {\n          chosen.dispatchEvent(new PointerEvent('pointerdown', { ...cinit, pointerType: 'mouse' }));\n          chosen.dispatchEvent(new MouseEvent('mousedown', cinit));\n          chosen.dispatchEvent(new PointerEvent('pointerup', { ...cinit, pointerType: 'mouse' }));\n          chosen.dispatchEvent(new MouseEvent('mouseup', cinit));\n          chosen.dispatchEvent(new MouseEvent('click', cinit));\n        } catch {}\n      });\n      return { ok: true, switched: true, chosen: chosenLabel, labels };\n    })()`));\n\n        if (!result.ok) {\n            throw new CommandExecutionError(result.reason, result.detail || '');\n        }\n        if (listOnly) {\n            return result.labels.map((m) => ({ Status: m === current ? 'Active' : 'Available', Model: m }));\n        }\n        const selected = findUniqueModelOption(result.labels || [], name);\n        if (!selected) {\n            throw new CommandExecutionError('No model matched.', `wanted=${name} available=${JSON.stringify(result.labels || [])}`);\n        }\n        if (selected !== result.chosen) {\n            throw new CommandExecutionError('Codex model selection was inconsistent.', `expected=${selected} chosen=${result.chosen}`);\n        }\n        let verified = '';\n        for (let attempt = 0; attempt < 20; attempt += 1) {\n            await page.wait(0.25);\n            const reread = unwrapEvaluateResult(await page.evaluate(`(function() {\n        const re = new RegExp(${patternJson});\n        const composers = Array.from(document.querySelectorAll('[contenteditable=\"true\"]')).filter((el) => el.offsetParent);\n        const last = composers[composers.length - 1];","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/codex/model.js#L207-L243","documentation":"Inside the `codex model` command, the in-page automation script returns `{ ok: false, reason, detail }` for any DOM-level failure (composer missing, trigger button not found, menu not opening, no/ambiguous match). The Node side rethrows that reason as a CommandExecutionError at this line, so this error carries whatever the browser script reported. It is the umbrella failure point for the click-and-select automation inside the Codex UI.","triggerScenarios":"Running `opencli codex model <name>` when the evaluate script sets ok:false: composer contenteditable not found, model trigger button not matched by MODEL_BTN_TEXT_RE, menu items didn't appear within ~1.3s of the synthetic click, or zero/ambiguous normalized label matches inside the page script.","commonSituations":"No chat open in Codex so no composer exists; a Codex update changed the composer toolbar DOM so the regex no longer matches; slow UI where the menu takes longer than the 16×80ms wait; synthetic clicks ignored by an updated menu component.","solutions":["Open a chat in Codex so the composer and model button are visible, then retry.","Run `opencli codex model --list` to test whether the menu can be opened at all; if it fails, the DOM drifted — update opencli.","Retry once; slow renders sometimes exceed the menu-open wait window.","Read the error's reason/detail (e.g. 'Model menu did not open after click.') to target the specific failing step."],"exampleFix":"// before\nopencli codex model \"gpt-5.5\"   // fails: 'model trigger button not found in composer'\n// after\n# open a chat first so the composer exists\nopencli codex model --list       # verify menu opens / DOM matches\nopencli codex model \"gpt-5.5\"","handlingStrategy":"retry","validationCode":"// ensure a chat/composer exists before switching\nconst current = await run('opencli codex model'); // throws selectorError if no composer\nif (!current) await openNewChat();","typeGuard":"function automationResultOk(r) { return r && typeof r === 'object' && r.ok === true; }","tryCatchPattern":"try {\n  await switchModel(name);\n} catch (err) {\n  if (err instanceof CommandExecutionError) {\n    // reason in err.message/detail; wait for UI and retry once\n    await sleep(2000);\n    return switchModel(name);\n  }\n  throw err;\n}","preventionTips":["Open a chat in Codex so the composer is present before switching","Retry once on menu-open timeouts; slow renders can exceed the wait window","Keep opencli updated when Codex changes composer/menu DOM","Use --list as a cheap health check of the automation path"],"tags":["browser-automation","ui-scraping","codex","model-selection"],"backgroundTag":"dom-automation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}