SeleniumHQ/selenium · error · TypeError

Custom locator did not return a WebElement

Error message

Custom locator did not return a WebElement

What it means

Thrown as a TypeError by WebDriver.findElementInternal_() when a custom locator function resolves to a value that is neither an array nor a WebElement instance. After calling locatorFn(context), the code checks `if (!(result instanceof WebElement))` and throws TypeError with the message 'Custom locator did not return a WebElement'. This is a contract violation: custom locators must return a WebElement or an array of WebElements.

Source

Thrown at javascript/selenium-webdriver/lib/webdriver.js:1054

  }

  /**
   * @param {!Function} locatorFn The locator function to use.
   * @param {!(WebDriver|WebElement)} context The search context.
   * @return {!Promise<!WebElement>} A promise that will resolve to a list of
   *     WebElements.
   * @private
   */
  async findElementInternal_(locatorFn, context) {
    let result = await locatorFn(context)
    if (Array.isArray(result)) {
      if (result.length === 0) {
        throw new NoSuchElementError('Cannot locate an element with provided parameters')
      }
      result = result[0]
    }
    if (!(result instanceof WebElement)) {
      throw new TypeError('Custom locator did not return a WebElement')
    }
    return result
  }

  /** @override */
  async findElements(locator) {
    let cmd = null
    if (locator instanceof RelativeBy) {
      cmd = new command.Command(command.Name.FIND_ELEMENTS_RELATIVE).setParameter('args', locator.marshall())
    } else {
      locator = by.checkedLocator(locator)
    }

    if (typeof locator === 'function') {
      return this.findElementsInternal_(locator, this)
    } else if (cmd === null) {
      cmd = new command.Command(command.Name.FIND_ELEMENTS)
        .setParameter('using', locator.using)

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Ensure the custom locator function returns a WebElement instance — use `return driver.findElement(By.css(selector))` or `return context.findElement(By.css(selector))` inside the function, not the raw selector or element data.
  2. If the locator returns an array, confirm every element in the array is a WebElement instance (the code will take result[0]).
  3. Add a return-type assertion or logging inside the locator function to verify the value before it reaches findElementInternal_.
  4. If you only need the element ID or raw data, use a different API (executeScript) instead of treating it as a WebElement locator.

Example fix

// before
driver.findElement(function(driver) {
  return driver.executeScript('return document.querySelector("#foo");')
  // executeScript returns a raw element or null, not a WebElement
})

// after
driver.findElement(function(driver) {
  return driver.findElement(By.id('foo'))  // returns a WebElement
})
Defensive patterns

Strategy: type-guard

Type guard

const { WebElement } = require('selenium-webdriver')
function isWebElement(v) {
  return v instanceof WebElement
}
// Inside a custom locator:
// const result = ...; if (!isWebElement(result)) throw new Error('locator bug')

Try / catch

try {
  const el = await driver.findElement(customLocatorFn)
} catch (e) {
  if (e instanceof TypeError && /Custom locator/.test(e.message)) {
    // fix the locator to return a WebElement
  } else throw e
}

Prevention

When it happens

Trigger: Defining a custom locator function (a function passed where a Locator is expected, e.g. driver.findElement(fn)) that returns a primitive, a plain object, a string, a Promise resolving to a non-WebElement, or undefined. The instanceof WebElement check fails on any such return.

Common situations: A custom locator returns a raw element ID or a JSON object instead of a WebElement wrapper; a locator function has a code path that returns undefined or null on an edge case; a developer misreads the locator API and returns a CSS selector string instead of performing the lookup.

Related errors


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/0c4326d144ab2468. Report an issue: GitHub.