{"record":{"id":"2d4f2b9f19125e2a","repo":"can1357/oh-my-pi","slug":"drag-selector-did-not-resolve-to-a-visible-element","errorCode":null,"errorMessage":"Drag selector did not resolve to a visible element: ${target}","messagePattern":"Drag selector did not resolve to a visible element: (.+?)","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts","lineNumber":1031,"sourceCode":"\t\t\tconst rect = element.getBoundingClientRect();\n\t\t\tif (rect.width <= 0 || rect.height <= 0) return null;\n\t\t\treturn { x: rect.x, y: rect.y, width: rect.width, height: rect.height };\n\t\t})()`;\n\t\tconst value = await this.#evalScript<unknown>(script);\n\t\tif (!value || typeof value !== \"object\") return null;\n\t\tconst object = value as Record<string, unknown>;\n\t\treturn {\n\t\t\tx: numberFrom(object.x, 0),\n\t\t\ty: numberFrom(object.y, 0),\n\t\t\twidth: numberFrom(object.width, 0),\n\t\t\theight: numberFrom(object.height, 0),\n\t\t};\n\t}\n\n\tasync #dragPoint(target: DragTarget): Promise<{ x: number; y: number }> {\n\t\tif (typeof target === \"string\") {\n\t\t\tconst box = await this.#selectorBox(this.#selectorSpec(target));\n\t\t\tif (!box) throw new ToolError(`Drag selector did not resolve to a visible element: ${target}`);\n\t\t\treturn { x: box.x + box.width / 2, y: box.y + box.height / 2 };\n\t\t}\n\t\tif (Number.isFinite(target.x) && Number.isFinite(target.y)) {\n\t\t\treturn { x: target.x, y: target.y };\n\t\t}\n\t\tthrow new ToolError(\"Drag target must be a selector string or { x: number, y: number } point\");\n\t}\n\n\tasync #installResponseObserver(): Promise<void> {\n\t\tawait this.#evalScript<boolean>(RESPONSE_OBSERVER_SCRIPT);\n\t}\n\n\tasync #responseCursor(): Promise<number> {\n\t\tconst value = await this.#evalScript<unknown>(\n\t\t\t\"(() => Math.max(0, ((globalThis.__ompCmuxResponses && globalThis.__ompCmuxResponses.nextId) || 1) - 1))()\",\n\t\t);\n\t\treturn numberFrom(value, 0);\n\t}","sourceCodeStart":1013,"sourceCodeEnd":1049,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts#L1013-L1049","documentation":"`#dragPoint` resolves a string drag target to a bounding box via `#selectorBox`; when the selector resolves to nothing visible (no box), it throws this ToolError. Dragging needs geometry (x/y center), so a detached, display:none, or non-existent element cannot be used as a drag source or destination.","triggerScenarios":"Dragging from/to a selector that matches no visible element: hidden element, zero-size element, wrong selector, or element not yet rendered when the drag starts.","commonSituations":"Drag-and-drop libraries that render only during drag (proxy handles); elements collapsed until hover; selector scoped to the wrong frame/page; animation delay leaving the element with an empty box.","solutions":["Confirm the selector resolves to a visible element (check offsetWidth/offsetHeight) and wait for it first with tab.waitFor.","Switch to explicit coordinates: pass { x, y } instead of a selector when the element has no stable box.","Fix the selector or scroll the element into view before dragging."],"exampleFix":"// before\ntab.drag('.item', '.dropzone');\n// after\nawait tab.waitFor('.item');\nawait tab.drag('.item:not(.hidden)', '.dropzone'); // target the actually visible node","handlingStrategy":"validation","validationCode":"const box = await tab.evaluate(`(() => { const el = document.querySelector(${JSON.stringify(sel)}); if (!el) return null; const r = el.getBoundingClientRect(); return (r.width > 0 && r.height > 0) ? { x: r.x, y: r.y, w: r.width, h: r.height } : null; })()`);\nif (!box) throw new Error(`drag source not visible: ${sel}`);","typeGuard":"function isVisibleBox(box: { width: number; height: number } | null | undefined): boolean { return !!box && box.width > 0 && box.height > 0; }","tryCatchPattern":null,"preventionTips":["waitFor the element before dragging it.","Scroll elements into view first; offscreen can still yield a box, but hidden ones do not.","For dynamically-rendered drag handles, prefer explicit { x, y } coordinates."],"tags":["drag-and-drop","selector","visibility","browser-automation"],"backgroundTag":"selector-not-visible","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}