SeleniumHQ/selenium · error · InvalidArgumentError

Invalid drag target; must specify a WebElement or {x, y} off

Error message

Invalid drag target; must specify a WebElement or {x, y} offset

What it means

Thrown by Actions.dragAndDrop() when the `to` argument is neither a WebElement nor a plain object with numeric x and y properties. The validation runs synchronously before any pointer action is emitted, so no partial input sequence is sent. It is an InvalidArgumentError (400 invalid argument).

Source

Thrown at javascript/selenium-webdriver/lib/input.js:942

   * 1.  Move to the center of the `from` element (element to be dragged).
   * 2.  Press the left mouse button.
   * 3.  If the `to` target is a {@linkplain ./webdriver.WebElement WebElement},
   *     move the mouse to its center. Otherwise, move the mouse by the
   *     specified offset.
   * 4.  Release the left mouse button.
   *
   * @param {!./webdriver.WebElement} from The element to press the left mouse
   *     button on to start the drag.
   * @param {(!./webdriver.WebElement|{x: number, y: number})} to Either another
   *     element to drag to (will drag to the center of the element), or an
   *     object specifying the offset to drag by, in pixels.
   * @return {!Actions} a self reference.
   */
  dragAndDrop(from, to) {
    // Do not require up top to avoid a cycle that breaks static analysis.
    const { WebElement } = require('./webdriver')
    if (!(to instanceof WebElement) && (!to || typeof to.x !== 'number' || typeof to.y !== 'number')) {
      throw new InvalidArgumentError('Invalid drag target; must specify a WebElement or {x, y} offset')
    }

    this.move({ origin: from }).press()
    if (to instanceof WebElement) {
      this.move({ origin: to })
    } else {
      this.move({ x: to.x, y: to.y, origin: Origin.POINTER })
    }
    return this.release()
  }

  /**
   * Releases all keys, pointers, and clears internal state.
   *
   * @return {!Promise<void>} a promise that will resolve when finished
   *     clearing all action state.
   */
  clear() {

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Pass a WebElement: dragAndDrop(srcEl, destEl).
  2. Pass numeric offsets: dragAndDrop(srcEl, {x: 10, y: 20}) where both are JS numbers.
  3. Coerce config-supplied values: {x: Number(cfg.dx), y: Number(cfg.dy)} and verify !isNaN before calling.
  4. If you only have a selector, resolve it to a WebElement first with driver.findElement(by).
  5. Confirm the object is a selenium WebElement (instanceof webdriver.WebElement), not a bare handle.

Example fix

// before
const cfg = JSON.parse(raw);
await driver.actions().dragAndDrop(src, cfg.offset); // throws if dx/dy are strings

// after
const offset = { x: Number(cfg.offset.x), y: Number(cfg.offset.y) };
if (Number.isNaN(offset.x) || Number.isNaN(offset.y)) throw new Error('bad offset');
await driver.actions().dragAndDrop(src, offset);
Defensive patterns

Strategy: type-guard

Validate before calling

function validateDragTarget(to, WebElement) {
  const isOffset =
    to && typeof to === 'object' &&
    typeof to.x === 'number' && typeof to.y === 'number' &&
    Number.isFinite(to.x) && Number.isFinite(to.y);
  if (!(to instanceof WebElement) && !isOffset) {
    throw new Error('drag target must be WebElement or {x:number,y:number}');
  }
}

Type guard

function isWebElementOrOffset(to, WebElement) {
  return (
    to instanceof WebElement ||
    (!!to && typeof to.x === 'number' && typeof to.y === 'number')
  );
}

Try / catch

try {
  await driver.actions().dragAndDrop(src, target).perform();
} catch (e) {
  if (e.name === 'InvalidArgumentError' && /drag target/i.test(e.message)) {
    // coerce numeric strings then retry
    target = { x: Number(target.x), y: Number(target.y) };
    await driver.actions().dragAndDrop(src, target).perform();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling actions.dragAndDrop(from, undefined), dragAndDrop(from, null), dragAndDrop(from, {x: '5', y: 6}) (string coordinate), dragAndDrop(from, {x: 5}) (missing y), or passing a non-WebElement element-like object (e.g. a plain locator). A valid WebElement or {x:number, y:number} passes.

Common situations: Reading a target from a config/JSON where numbers arrive as strings; passing a DOM element handle from another framework instead of a selenium WebElement; typo'ing the coordinate object keys (e.g. {X, Y}); assuming the second arg is optional.

Related errors


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