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
- Pass a WebElement: dragAndDrop(srcEl, destEl).
- Pass numeric offsets: dragAndDrop(srcEl, {x: 10, y: 20}) where both are JS numbers.
- Coerce config-supplied values: {x: Number(cfg.dx), y: Number(cfg.dy)} and verify !isNaN before calling.
- If you only have a selector, resolve it to a WebElement first with driver.findElement(by).
- 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
- Coerce config-loaded coordinates with Number() and check Number.isFinite before calling.
- Keep WebElement imports from webdriver so instanceof checks work.
- Never assume the second argument is optional.
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
- key is not a string: ${key}
- key input is not a single code point: ${key}
- Invalid PointerInput kind '{kind}'
- Unexpected compiled output format. Expected it to start with
- Unexpected compiled output format. Expected it to start with
AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14).
Data as JSON: /api/errors/aeeee7bd0221d8ce.
Report an issue: GitHub.