jackwener/OpenCLI · error · CommandExecutionError

ChatGPT model did not switch to ${target.label}.

Error message

ChatGPT model did not switch to ${target.label}.

What it means

After clicking the option, the library verifies via getCurrentChatGPTModel (and, for intelligence-ordered models, the checked item's order in the reopened menu) that the active model actually changed to target. If the verification fails it closes the menu and throws CommandExecutionError. This is a post-condition check, not a click failure.

Source

Thrown at clis/chatgpt/utils.js:761

                return rect.width > 0 && rect.height > 0;
            };
            const target = ${JSON.stringify(target)};
            const intelligenceContent = document.querySelector('[data-testid="composer-intelligence-picker-content"]');
            const options = intelligenceContent
                ? Array.from(intelligenceContent.querySelectorAll('[role="menuitemradio"]')).filter(isVisible)
                : [];
            const checkedIndex = options.findIndex((node) => node.getAttribute('aria-checked') === 'true');
            return {
                recognized: options.length === 5 && Number.isInteger(target.intelligenceOrder),
                checkedIndex,
            };
        })()`)), 'chatgpt model checked intelligence option');
        if (checked.recognized && checked.checkedIndex === target.intelligenceOrder) {
            await page.nativeClick(Number(menuButton.x), Number(menuButton.y));
            return { Status: 'Success', Model: target.label };
        }
        await page.nativeClick(Number(menuButton.x), Number(menuButton.y));
        throw new CommandExecutionError(`ChatGPT model did not switch to ${target.label}.`);
    }
    return { Status: 'Success', Model: target.label };
}

export async function getCurrentChatGPTTool(page) {
    return requireObjectEvaluateResult(unwrapEvaluateResult(await page.evaluate(`(() => {
        const isVisible = (el) => {
            if (!(el instanceof HTMLElement)) return false;
            const style = window.getComputedStyle(el);
            if (style.display === 'none' || style.visibility === 'hidden') return false;
            const rect = el.getBoundingClientRect();
            return rect.width > 0 && rect.height > 0;
        };
            const normalize = (value) => String(value || '').replace(/\\s+/g, ' ').trim();
            const compact = (value) => normalize(value).toLowerCase().replace(/[^\\p{L}\\p{N}]+/gu, '');
            const matchesLabel = (value, labels) => {
                const normalized = normalize(value).toLowerCase();
                const compacted = compact(value);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-read the model with getCurrentChatGPTModel after a short wait — the switch may just settle late.
  2. Retry the selection once; transient races are common on slow sessions.
  3. Verify the account entitlement for the requested tier so ChatGPT doesn't revert it.
  4. Set OPENCLI_CHATGPT_MODEL_DEBUG=1 to see the before/after model reads and the checked index.

Example fix

// before
await selectChatGPTModel(page, 'advanced'); // may throw on slow settle
// after
try {
  await selectChatGPTModel(page, 'advanced');
} catch (err) {
  if (err.message.includes('did not switch to')) {
    await page.wait(2);
    const cur = await getCurrentChatGPTModel(page);
    if (cur.model === 'advanced') return cur; // switched after all
  }
  throw err;
}
Defensive patterns

Strategy: retry

Validate before calling

const before = await getCurrentChatGPTModel(page);
if (before.model === targetKey) return; // already active, nothing to do

Type guard

function switchedTo(current, targetKey) {
  return current != null && current.model === targetKey;
}

Try / catch

try {
  await selectChatGPTModel(page, model);
} catch (err) {
  if (err instanceof CommandExecutionError && /did not switch to/.test(err.message)) {
    await page.wait(2);
    const after = await getCurrentChatGPTModel(page); // re-read after settling
    if (after.model === expectedKey) return after; // eventual consistency
    throw err;
  }
  throw err;
}

Prevention

When it happens

Trigger: The click landed but the model didn't switch: the click hit a disabled/partially rendered option, ChatGPT reverted the preference server-side (entitlement or session issue), the current-model read raced ahead of the UI update, or for intelligenceOrder targets the checked index didn't match target.intelligenceOrder.

Common situations: Paid tiers silently unavailable so ChatGPT reverts the preference; click landing during a menu re-render; verification racing the UI update; for intelligence-ordered models the checked index not matching target.intelligenceOrder.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/3523deebd1dbddf6. Report an issue: GitHub.