jackwener/OpenCLI · error · CommandExecutionError
No model matched
Error message
No model matched: '${name}' What it means
This error is thrown by the trae-solo `model` command when the model-switch name argument does not case-insensitively match any option label in Trae's opened model dropdown. The command first enumerates visible `.core-model-select-model-item[role="option"]` labels via page.evaluate, then finds an index whose label contains the requested substring; if findIndex returns -1 it closes the menu and throws CommandExecutionError, attaching the list of available labels as the detail. It exists to fail fast with actionable context instead of clicking an undefined option.
Solutions
- Run the command with `--list` (or no name) to see the exact available labels and re-run with a matching substring.
- Use a shorter, unambiguous substring of the label shown in the detail's available=[...] array.
- Verify the model actually exists in this Trae workspace/plan; request access or pick another model.
- Update the tooling if Trae renamed model entries so docs/aliases match new labels.
Example fix
// before
await cli('trae-solo', 'model', 'claude-3-5-sonnet');
// after
const opts = await cli('trae-solo', 'model', { list: true });
const target = opts.find(m => /claude/i.test(m.Model));
if (target) await cli('trae-solo', 'model', target.Model); Defensive patterns
Strategy: validation
Validate before calling
const listed = await cli('trae-solo', 'model', { list: true });
if (!listed.some(m => m.Model.toLowerCase().includes(name))) {
throw new Error(`'${name}' not offered. Options: ${listed.map(m => m.Model).join(', ')}`);
} Type guard
const hasModel = (labels, name) => Array.isArray(labels) && labels.some(l => typeof l === 'string' && l.toLowerCase().includes(name.toLowerCase()));
Try / catch
try {
await cli('trae-solo', 'model', name);
} catch (e) {
if (/No model matched/.test(e.message)) {
console.warn('Available:', e.detail); // detail carries available=[...]
} else throw e;
} Prevention
- Always run --list first when unsure of exact model labels.
- Match on short, distinctive substrings rather than full marketing names.
- Keep an alias map from model names you use to labels Trae displays.
- Re-check the available list after Trae updates.
When it happens
Trigger: Calling `model <name>` where <name> is a substring not contained in any currently rendered model menu label — e.g. misspelling, wrong casing assumptions beyond case-insensitivity, a model not provisioned in this Trae workspace, or the menu rendering a truncated/renamed label set.
Common situations: Developers request a model by its marketing name (e.g. 'gpt-4o') while the Trae menu shows a different display label; org policies hide certain models; Trae updated and renamed menu entries; or the menu failed to fully render so only a partial label list was captured.
Related errors
- Model click did not verify selected model
- Click on model option failed.
- SELECTOR
- Visible Midjourney control
- Add Workspace button not found
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/18a06df6a9f94872.
Report an issue: GitHub.
Appendix: source
Thrown at clis/trae-solo/model.js:88
return { ok: true, labels };
})()`);
if (!stage1.ok) {
throw new CommandExecutionError(stage1.reason, stage1.detail || '');
}
if (listOnly) {
try { await page.evaluate('document.body.click()'); } catch {}
return stage1.labels.map((m) => ({ Status: m === current ? 'Active' : 'Available', Model: m }));
}
// Stage 2 (page.click): use real CDP Input.dispatchMouseEvent —
// Trae's model menu items don't fire React onSelect from synthetic
// pointer events alone. Match by nth-of-type derived from labels.
const idx = stage1.labels.findIndex((l) => l.toLowerCase().includes(name));
if (idx < 0) {
try { await page.evaluate('document.body.click()'); } catch {}
throw new CommandExecutionError(
`No model matched: '${name}'`,
'available=' + JSON.stringify(stage1.labels),
);
}
const chosenLabel = stage1.labels[idx];
const clickSelector = `.core-model-select-model-item[role="option"]:nth-of-type(${idx + 1})`;
try {
await page.click(clickSelector);
} catch (err) {
// Some Trae model rows wrap option in another element; fall back
// to JS dispatch on the nth visible option.
const fallbackClicked = await page.evaluate(`(function(i) {
const opts = Array.from(document.querySelectorAll('.core-model-select-model-item[role="option"]'))
.filter((el) => el.offsetParent);
const target = opts[i];
if (!target) return false;
const r = target.getBoundingClientRect();
const init = { bubbles: true, cancelable: true, button: 0, buttons: 1,View on GitHub (pinned to 49907e53dc)