can1357/oh-my-pi · error · ToolError
Drag ${role} element has no bounding box (likely not visible
Error message
Drag ${role} element has no bounding box (likely not visible): ${target} What it means
After resolving a drag endpoint selector to an element, the worker calls boundingBox(). A null box means the element is not rendered in layout (display:none, detached, or zero-size), so no drag point can be computed. The handle is disposed and this ToolError names the failing endpoint and target.
Source
Thrown at packages/coding-agent/src/tools/browser/tab-worker.ts:1988
const resolveDragPoint = async (
target: DragTarget,
role: "from" | "to",
): Promise<{ x: number; y: number; handle?: ElementHandle }> => {
if (typeof target === "string") {
const handle =
parseAriaRefSelector(target) !== null
? await this.#resolveAriaRef(target)
: asElementHandle(await untilAborted(signal, () => page.$(normalizeSelector(target))));
if (!handle) throw new ToolError(`Drag ${role} selector did not resolve: ${target}`);
const box = (await untilAborted(signal, () => handle.boundingBox())) as {
x: number;
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 {View on GitHub (pinned to 9690622007)
Solutions
- Make the element visible before dragging (open its container/accordion, remove display:none).
- Verify the element is attached and has size via getBoundingClientRect() before calling drag.
- Use { x, y } coordinates of a visible proxy element instead of the hidden one.
- For offscreen elements, scroll the container first, re-observe, then drag with the fresh ref.
Example fix
// before
await tab.drag({ from: "#hidden-handle", to: "#drop" }); // #hidden-handle is display:none
// after
await tab.evaluate(() => { document.querySelector("#panel").classList.add("open"); });
await tab.drag({ from: "#hidden-handle", to: "#drop" }); Defensive patterns
Strategy: validation
Validate before calling
const visible = await tab.evaluate((sel) => {
const el = document.querySelector(sel);
return !!el && !!el.getBoundingClientRect().width && !!el.getBoundingClientRect().height;
}, selector);
if (!visible) throw new Error(`drag endpoint not visible: ${selector}`); Try / catch
try {
await tab.drag({ from, to });
} catch (err) {
if (err.message.includes("no bounding box")) {
await tab.evaluate((sel) => (document.querySelector(sel))?.scrollIntoView(), targetSelector);
return tab.drag({ from, to });
}
throw err;
} Prevention
- Scroll elements into view before dragging
- Open containers/accordions that hide the endpoint
- Check getBoundingClientRect() width/height before the call
- Use visible proxy elements or coordinates when the true target is hidden
When it happens
Trigger: tab.drag() with a selector endpoint whose element has no layout box: hidden via display:none/visibility:hidden, detached from the document, inside a collapsed container, or the element exists only in another frame so its box cannot be computed.
Common situations: Dragging from a hidden template node; target inside a closed accordion/modal; element scrolled far offscreen in a virtualized list and recycled; CSS media/state (e.g. hover-only menus) hiding the element at call time.
Related errors
- Drag ${role} selector did not resolve: ${target}
- Drag ${role} must be a selector string or { x: number, y: nu
- Browser selector must be a string; got ${kind}. tab.click/ty
- tab.ariaSnapshot: selector ${__sel} matched no element
- Timed out waiting for CDP endpoint ${cdpUrl}${lastStatus !==
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/115b89396bb5b6a5.
Report an issue: GitHub.