can1357/oh-my-pi · error · ToolError

Drag ${role} must be a selector string or { x: number, y: nu

Error message

Drag ${role} must be a selector string or { x: number, y: number } point. Got: ${typeof target}

What it means

The drag point resolver accepts only a selector string or a { x, y } numeric point object. Anything else (number, null, array, object missing x/y) fails this ToolError, which reports the offending typeof. This is an argument-shape validation error thrown before any mouse interaction.

Source

Thrown at packages/coding-agent/src/tools/browser/tab-worker.ts:2000

					y: number;
					width: number;
					height: number;
				} | null;
				if (!box) {
					await handle.dispose().catch(() => undefined);
					throw new ToolError(`Drag ${role} element has no bounding box (likely not visible): ${target}`);
				}
				return { x: box.x + box.width / 2, y: box.y + box.height / 2, handle };
			}
			if (
				target !== null &&
				typeof target === "object" &&
				typeof (target as { x: unknown }).x === "number" &&
				typeof (target as { y: unknown }).y === "number"
			) {
				return { x: (target as { x: number }).x, y: (target as { y: number }).y };
			}
			throw new ToolError(
				`Drag ${role} must be a selector string or { x: number, y: number } point. Got: ${typeof target}`,
			);
		};
		const start = await resolveDragPoint(from, "from");
		let end: { x: number; y: number; handle?: ElementHandle } | undefined;
		try {
			end = await resolveDragPoint(to, "to");
			await untilAborted(signal, () => page.mouse.move(start.x, start.y));
			await untilAborted(signal, () => page.mouse.down());
			await untilAborted(signal, () => page.mouse.move(end!.x, end!.y, { steps: 12 }));
			await untilAborted(signal, () => page.mouse.up());
		} finally {
			if (start.handle) await start.handle.dispose().catch(() => undefined);
			if (end?.handle) await end.handle.dispose().catch(() => undefined);
		}
	}

	async #select(selector: string, values: string[], timeoutMs: number, signal: AbortSignal): Promise<string[]> {

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass each endpoint as a selector string or as { x: number, y: number } with both fields numeric.
  2. Convert other shapes yourself: arrays to { x: a[0], y: a[1] }, bbox objects already satisfy x/y.
  3. Check the tab.drag() signature in the tool schema and match it exactly.
  4. If coordinates come from computed values, validate typeof x === "number" && typeof y === "number" before the call.

Example fix

// before
await tab.drag({ from: [120, 40], to: "#drop" });
// after
await tab.drag({ from: { x: 120, y: 40 }, to: "#drop" });
Defensive patterns

Strategy: validation

Validate before calling

function assertDragPoint(p: unknown): asserts p is string | { x: number; y: number } {
  if (typeof p === "string") return;
  if (p && typeof p === "object" && typeof (p as any).x === "number" && typeof (p as any).y === "number") return;
  throw new TypeError(`drag endpoint must be selector string or {x,y}; got ${typeof p}`);
}
assertDragPoint(from); assertDragPoint(to);

Type guard

function isPoint(p: unknown): p is { x: number; y: number } {
  return !!p && typeof p === "object" && typeof (p as any).x === "number" && typeof (p as any).y === "number";
}

Try / catch

try {
  await tab.drag({ from, to });
} catch (err) {
  if (err.message.includes("must be a selector string or")) {
    throw new Error(`bad drag args: from=${JSON.stringify(from)} to=${JSON.stringify(to)}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: tab.drag({ from: 123, to: ... }), from: null, { from: { x: 10 } } (missing y), or passing DOM element handles/position objects from another API instead of plain { x, y }.

Common situations: Passing a bounding-box object (x,y,width,height) — that is accepted, but a point array like [10, 20] or a string of "x,y" is not; JSON args built by an LLM with the wrong shape; copying options from a different library's drag API.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/9d0064e83186d320. Report an issue: GitHub.