jackwener/OpenCLI · error · CommandExecutionError
No model matched.
Error message
No model matched.
What it means
After the page script clicks the menu item, the Node side independently re-resolves the requested name against the scraped labels via `findUniqueModelOption`. This CommandExecutionError is thrown when that re-resolution finds no label (exact or substring) matching the requested name, meaning the wanted model/reasoning option was not present among the menu items actually scraped.
Source
Thrown at clis/codex/model.js:232
chosen.dispatchEvent(new PointerEvent('pointerdown', { ...cinit, pointerType: 'mouse' }));
chosen.dispatchEvent(new MouseEvent('mousedown', cinit));
chosen.dispatchEvent(new PointerEvent('pointerup', { ...cinit, pointerType: 'mouse' }));
chosen.dispatchEvent(new MouseEvent('mouseup', cinit));
chosen.dispatchEvent(new MouseEvent('click', cinit));
} catch {}
});
return { ok: true, switched: true, chosen: chosenLabel, labels };
})()`));
if (!result.ok) {
throw new CommandExecutionError(result.reason, result.detail || '');
}
if (listOnly) {
return result.labels.map((m) => ({ Status: m === current ? 'Active' : 'Available', Model: m }));
}
const selected = findUniqueModelOption(result.labels || [], name);
if (!selected) {
throw new CommandExecutionError('No model matched.', `wanted=${name} available=${JSON.stringify(result.labels || [])}`);
}
if (selected !== result.chosen) {
throw new CommandExecutionError('Codex model selection was inconsistent.', `expected=${selected} chosen=${result.chosen}`);
}
let verified = '';
for (let attempt = 0; attempt < 20; attempt += 1) {
await page.wait(0.25);
const reread = unwrapEvaluateResult(await page.evaluate(`(function() {
const re = new RegExp(${patternJson});
const composers = Array.from(document.querySelectorAll('[contenteditable="true"]')).filter((el) => el.offsetParent);
const last = composers[composers.length - 1];
if (!last) return '';
let root = last;
for (let i = 0; i < 5; i++) root = root.parentElement || root;
const btns = Array.from(root.querySelectorAll('button')).filter((b) => b.offsetParent);
const match = btns.find((b) => re.test((b.textContent || '').trim()));
return match ? (match.textContent || '').trim() : '';
})()`));View on GitHub (pinned to 49907e53dc)
Solutions
- Run `opencli codex model --list` and use an exact label from the output.
- Check the error detail (wanted=... available=...) and correct the spelling/format of the requested name.
- Update Codex or opencli if the model you want genuinely isn't listed.
- If the label is visible in the UI but missing from --list, report/patch the label-filtering logic (new unfiltered chat-action entries or kbd-removal drift).
Example fix
// before opencli codex model "gpt-5.6" // not in menu // after opencli codex model --list opencli codex model "gpt-5.5" # pick a listed label
Defensive patterns
Strategy: validation
Validate before calling
const listed = await run('opencli codex model --list');
const labels = parseLabels(listed);
const norm = s => s.toLowerCase().replace(/\bgpt[-\s]*/g,'').replace(/\s+/g,' ').trim();
if (!labels.some(l => norm(l).includes(norm(wanted)))) {
throw new Error(`"${wanted}" not offered; available: ${labels.join(', ')}`);
} Type guard
function labelExists(labels, name) {
const n = s => s.toLowerCase().replace(/\bgpt[-\s]*/g,'').replace(/\s+/g,' ').trim();
return labels.some(l => n(l) === n(name) || n(l).includes(n(name)));
} Try / catch
try {
await switchModel(name);
} catch (err) {
if (err instanceof CommandExecutionError && err.detail?.startsWith('wanted=')) {
// parse available= JSON from detail, surface valid options to the user
} else throw err;
} Prevention
- Resolve names against `codex model --list` before switching
- Keep model names in config in sync with what your Codex build offers
- Check the wanted=/available= detail to correct typos
- Update Codex/opencli when requesting newly released models
When it happens
Trigger: Running `opencli codex model <name>` with a name that doesn't correspond to any visible menu item — typo'd model names, requesting a model not offered on the account, or the page script's label filtering (kbd removal, chat-action exclusion) dropping the relevant item.
Common situations: Typo or wrong naming convention ('gpt55' vs 'GPT-5.5'); requesting a newer model than the Codex build offers; account tier lacking the model; Codex renaming menu labels after an update.
Related errors
- model name cannot be empty
- Model name "${rawName}" is ambiguous.
- ${result.reason}
- Codex model selection was inconsistent.
- Codex model switch to "${selected}" was not verified.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/306355ed33de85bc.
Report an issue: GitHub.