{"record":{"id":"0c4326d144ab2468","repo":"SeleniumHQ/selenium","slug":"custom-locator-did-not-return-a-webelement","errorCode":null,"errorMessage":"Custom locator did not return a WebElement","messagePattern":"Custom locator did not return a WebElement","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"javascript/selenium-webdriver/lib/webdriver.js","lineNumber":1054,"sourceCode":"  }\n\n  /**\n   * @param {!Function} locatorFn The locator function to use.\n   * @param {!(WebDriver|WebElement)} context The search context.\n   * @return {!Promise<!WebElement>} A promise that will resolve to a list of\n   *     WebElements.\n   * @private\n   */\n  async findElementInternal_(locatorFn, context) {\n    let result = await locatorFn(context)\n    if (Array.isArray(result)) {\n      if (result.length === 0) {\n        throw new NoSuchElementError('Cannot locate an element with provided parameters')\n      }\n      result = result[0]\n    }\n    if (!(result instanceof WebElement)) {\n      throw new TypeError('Custom locator did not return a WebElement')\n    }\n    return result\n  }\n\n  /** @override */\n  async findElements(locator) {\n    let cmd = null\n    if (locator instanceof RelativeBy) {\n      cmd = new command.Command(command.Name.FIND_ELEMENTS_RELATIVE).setParameter('args', locator.marshall())\n    } else {\n      locator = by.checkedLocator(locator)\n    }\n\n    if (typeof locator === 'function') {\n      return this.findElementsInternal_(locator, this)\n    } else if (cmd === null) {\n      cmd = new command.Command(command.Name.FIND_ELEMENTS)\n        .setParameter('using', locator.using)","sourceCodeStart":1036,"sourceCodeEnd":1072,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/javascript/selenium-webdriver/lib/webdriver.js#L1036-L1072","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","If the locator returns an array, confirm every element in the array is a WebElement instance (the code will take result[0]).","Add a return-type assertion or logging inside the locator function to verify the value before it reaches findElementInternal_.","If you only need the element ID or raw data, use a different API (executeScript) instead of treating it as a WebElement locator."],"exampleFix":"// before\ndriver.findElement(function(driver) {\n  return driver.executeScript('return document.querySelector(\"#foo\");')\n  // executeScript returns a raw element or null, not a WebElement\n})\n\n// after\ndriver.findElement(function(driver) {\n  return driver.findElement(By.id('foo'))  // returns a WebElement\n})","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const { WebElement } = require('selenium-webdriver')\nfunction isWebElement(v) {\n  return v instanceof WebElement\n}\n// Inside a custom locator:\n// const result = ...; if (!isWebElement(result)) throw new Error('locator bug')","tryCatchPattern":"try {\n  const el = await driver.findElement(customLocatorFn)\n} catch (e) {\n  if (e instanceof TypeError && /Custom locator/.test(e.message)) {\n    // fix the locator to return a WebElement\n  } else throw e\n}","preventionTips":["Custom locator functions must return a WebElement or array of WebElements — never primitives or plain objects.","Use driver.findElement(By...) inside custom locators, not executeScript with raw DOM returns.","Add a type assertion at the end of custom locator functions during development."],"tags":["javascript","locators","custom-locator","type-error","webdriver"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}