{"record":{"id":"c03da071330aa43c","repo":"JuliusBrussee/caveman","slug":"missing-backend-dom-node-id","errorCode":null,"errorMessage":"missing backend DOM node id","messagePattern":"missing backend DOM node id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"browse/cdp.go","lineNumber":303,"sourceCode":"\t\t}\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn 0, 0, ctx.Err()\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t}\n\t}\n}\n\ntype boxPoint struct {\n\tx float64\n\ty float64\n\tw float64\n\th float64\n}\n\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]","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/browse/cdp.go#L285-L321","documentation":"Returned by CDPDriver.box() when target.BackendDOMNodeID <= 0. Geometry (center x/y, width, height) is fetched via dom.GetBoxModel().WithBackendNodeID, which requires a real backend node id; a Target without one (never resolved from a snapshot, or zero-valued) cannot be measured, so the driver fails closed instead of issuing a CDP call with id 0.","triggerScenarios":"Calling an action or eval path that needs element geometry (click point calculation, bounding-box checks) with a Target struct whose BackendDOMNodeID was never populated — e.g. a uid target built from stale snapshot metadata after a page navigation, or a hand-constructed Target.","commonSituations":"Acting on a uid from an old snapshot after the page changed; race between snapshot and act; recovery metadata decoded from an expired handle.","solutions":["Take a fresh snapshot (which rebuilds uid -> BackendDOMNodeID mappings) and retry the action with the new uid.","If you build Target values yourself, resolve them through the driver's snapshot path so BackendDOMNodeID is set.","Treat this as a stale-handle signal: the element reference must be re-acquired, not retried as-is."],"exampleFix":"// before\nact(target: \"uid-42\", action: \"click\")  // page navigated; uid map stale\n\n// after\nsnapshot()  // refreshes uid -> BackendDOMNodeID\nact(target: \"<new-uid>\", action: \"click\")","handlingStrategy":"validation","validationCode":"// Go: only attempt box-dependent actions on targets resolved from a live snapshot\nfunc hasBackendNode(t Target) bool {\n    return t.BackendDOMNodeID > 0\n}","typeGuard":"func actionableTarget(t Target) (Target, bool) {\n    return t, t.BackendDOMNodeID > 0\n}","tryCatchPattern":null,"preventionTips":["Re-snapshot after any navigation before issuing geometry-dependent actions.","Never construct Target values by hand; take them from the driver's snapshot uid map.","Treat BackendDOMNodeID == 0 as 'stale handle — re-acquire', not as retryable."],"tags":["browser","cdp","dom","stale-reference"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}