{"record":{"id":"ce25a04611841729","repo":"JuliusBrussee/caveman","slug":"box-model-has-no-quad","errorCode":null,"errorMessage":"box model has no quad","messagePattern":"box model has no quad","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"browse/cdp.go","lineNumber":318,"sourceCode":"\nfunc (d *CDPDriver) box(ctx context.Context, target Target) (float64, float64, float64, float64, error) {\n\tif target.BackendDOMNodeID <= 0 {\n\t\treturn 0, 0, 0, 0, errors.New(\"missing backend DOM node id\")\n\t}\n\tvar model *dom.BoxModel\n\tif err := chromedp.Run(ctx, chromedp.ActionFunc(func(actionCtx context.Context) error {\n\t\tvar err error\n\t\tmodel, err = dom.GetBoxModel().WithBackendNodeID(cdp.BackendNodeID(target.BackendDOMNodeID)).Do(actionCtx)\n\t\treturn err\n\t})); err != nil {\n\t\treturn 0, 0, 0, 0, err\n\t}\n\tquad := model.Content\n\tif len(quad) < 8 {\n\t\tquad = model.Border\n\t}\n\tif len(quad) < 8 {\n\t\treturn 0, 0, 0, 0, errors.New(\"box model has no quad\")\n\t}\n\tminX, maxX := quad[0], quad[0]\n\tminY, maxY := quad[1], quad[1]\n\tfor i := 0; i+1 < len(quad); i += 2 {\n\t\tminX = math.Min(minX, quad[i])\n\t\tmaxX = math.Max(maxX, quad[i])\n\t\tminY = math.Min(minY, quad[i+1])\n\t\tmaxY = math.Max(maxY, quad[i+1])\n\t}\n\treturn (minX + maxX) / 2, (minY + maxY) / 2, maxX - minX, maxY - minY, nil\n}\n\nfunc (d *CDPDriver) visible(ctx context.Context, target Target) (bool, error) {\n\treturn d.callBoolOnNode(ctx, target, `function(){ const s = window.getComputedStyle(this); const r = this.getBoundingClientRect(); return !!s && s.display !== \"none\" && s.visibility !== \"hidden\" && s.pointerEvents !== \"none\" && Number(s.opacity || \"1\") > 0 && r.width > 0 && r.height > 0; }`)\n}\n\nfunc (d *CDPDriver) enabled(ctx context.Context, target Target) (bool, error) {\n\treturn d.callBoolOnNode(ctx, target, `function(){ return !(this.disabled === true || this.getAttribute(\"disabled\") !== null || this.getAttribute(\"aria-disabled\") === \"true\" || this.closest(\"[inert]\")); }`)","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/browse/cdp.go#L300-L336","documentation":"After fetching the DOM box model, box needs a coordinate quad (8 floats: 4 x/y points). It prefers the content quad and falls back to the border quad; if both are shorter than 8 elements the model carries no usable geometry, so it fails with 'box model has no quad' rather than computing a garbage bounding box from partial coordinates.","triggerScenarios":"dom.GetBoxModel returns a BoxModel whose Content and Border slices both have fewer than 8 entries — e.g. the node is display:none, detached from layout, or not rendered — when box is invoked via waitActionable.","commonSituations":"Clicking/typing on a hidden element (display:none or visibility tricks) that produces an empty box model; an element inside a collapsed or not-yet-laid-out subtree; a detached node whose backend id still resolves but has no geometry; viewport/iframes edge cases where layout is skipped.","solutions":["Ensure the element is visible and rendered (scroll it into view, remove display:none) before performing actions on it","Re-query the element after layout settles; wait for the page/element to be actionable instead of acting immediately","If the node is stale/detached, re-resolve it to a fresh backend node id and retry","Fall back to an alternative geometry source (e.g. getBoundingClientRect via Runtime.evaluate) if the CDP box model stays empty"],"exampleFix":"// before\nawait page.Click(\"#hidden-panel\") // display:none -> empty quad\n// after\nawait page.Eval(\"document.querySelector('#hidden-panel').style.display='block'\")\nawait page.Click(\"#hidden-panel\")","handlingStrategy":"retry","validationCode":"// guard: only act on elements expected to be rendered\nfunc expectVisible(sel string) error {\n    if !isDisplayed(sel) { return fmt.Errorf(\"%s not rendered; skip action\", sel) }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"x, y, w, h, err := d.box(ctx, target)\nif err != nil {\n    if err.Error() == \"box model has no quad\" {\n        // element hidden or not laid out: make visible / re-resolve, then retry once\n        return d.retryAfterVisible(ctx, target)\n    }\n    return err\n}","preventionTips":["Wait for elements to be visible/actionable before clicking or typing","Avoid acting on display:none or detached nodes; re-resolve after DOM updates","Scroll elements into view first so layout geometry exists","If quad errors persist, fall back to getBoundingClientRect via JS evaluation"],"tags":["browser-automation","cdp","layout","geometry"],"backgroundTag":"unexpected-response-shape","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}