SeleniumHQ/selenium · error · Error
Select only works on <select> elements
Error message
Select only works on <select> elements
What it means
Thrown inside a `.then()` callback in the Select constructor when the element's tagName is not 'select'. IMPORTANT: the throw occurs inside an un-awaited promise — the constructor does not return or await it, so the rejection becomes an unhandled promise rejection (or surfaces later, detached from the call site). Users may see a confusing async error rather than a clean constructor failure.
Source
Thrown at javascript/selenium-webdriver/lib/select.js:157
/**
* @implements ISelect
*/
class Select {
/**
* Create an Select Element
* @param {WebElement} element Select WebElement.
*/
constructor(element) {
if (element === null) {
throw new Error(`Element must not be null. Please provide a valid <select> element.`)
}
this.element = element
this.element.getAttribute('tagName').then(function (tagName) {
if (tagName.toLowerCase() !== 'select') {
throw new Error(`Select only works on <select> elements`)
}
})
this.element.getAttribute('multiple').then((multiple) => {
this.multiple = multiple !== null && multiple !== 'false'
})
}
/**
*
* Select option with specified index.
*
* <example>
<select id="selectbox">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>View on GitHub (pinned to aa36b38e69)
Solutions
- Verify the tag before constructing: const tag = await el.getTagName(); if (tag !== 'select') throw new Error('not a select');
- Use a locator scoped to selects: By.css('select#myid') so the wrong tag cannot match.
- Because the constructor's check is async and detached, perform your own synchronous-able pre-check and don't rely on the constructor to validate.
- Register a global unhandledRejection handler so a missed check surfaces loudly during dev.
Example fix
// before
const el = await driver.findElement(By.id('qty')); // a <div id="qty">
const sel = new Select(el); // async unhandled rejection
// after
const el = await driver.findElement(By.css('select#qty'));
// or guard:
if ((await el.getTagName()) !== 'select') throw new Error('element is not a <select>');
const sel = new Select(el); Defensive patterns
Strategy: validation
Validate before calling
async function safeSelect(el) {
const tag = (await el.getTagName()).toLowerCase();
if (tag !== 'select') {
throw new Error(`expected <select>, got <${tag}>`);
}
return new Select(el);
} Type guard
async function isSelectElement(el) {
return (await el.getTagName()).toLowerCase() === 'select';
} Try / catch
process.on('unhandledRejection', (reason) => {
if (reason instanceof Error && /Select only works on/.test(reason.message)) {
log.error('Select created on a non-select element');
}
});
// Prefer pre-validation rather than catching this detached rejection. Prevention
- Scope locators to selects: By.css('select#id') so wrong tags cannot match.
- Pre-check getTagName() because the constructor's check is async/detached.
- Add a global unhandledRejection handler in dev to surface detached throws.
When it happens
Trigger: new Select(divElement); new Select(textareaElement); new Select(inputElement); any element whose tagName.toLowerCase() !== 'select'.
Common situations: Locating an element by an id that exists but is a different tag; generic form helpers that wrap any element in Select; copied locators that match the wrong element after a DOM refactor.
Related errors
- Element must not be null. Please provide a valid <select> el
- Select element doesn't contain any option element
- You may only deselect all options of a multi-select
- Index needs to be 0 or any other positive number
- Option with index "${index}" not found. Select element only
AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14).
Data as JSON: /api/errors/35b1c6b9c1a425e4.
Report an issue: GitHub.