{"record":{"id":"8d795f5c1a892ddc","repo":"grafana/k6","slug":"getting-position-of-parent-frame-w","errorCode":null,"errorMessage":"getting position of parent frame: %w","messagePattern":"getting position of parent frame: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/element_handle.go","lineNumber":83,"sourceCode":"\tvar err error\n\taction := dom.GetBoxModel().WithObjectID(h.remoteObject.ObjectID)\n\tif box, err = action.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting bounding box model of DOM node: %w\", err)\n\t}\n\n\tif box == nil || box.Border == nil {\n\t\treturn nil, ErrElementNotAttachedToDOM\n\t}\n\n\tquad := box.Border\n\tx := math.Min(quad[0], math.Min(quad[2], math.Min(quad[4], quad[6])))\n\ty := math.Min(quad[1], math.Min(quad[3], math.Min(quad[5], quad[7])))\n\twidth := math.Max(quad[0], math.Max(quad[2], math.Max(quad[4], quad[6]))) - x\n\theight := math.Max(quad[1], math.Max(quad[3], math.Max(quad[5], quad[7]))) - y\n\n\tposition, err := h.frame.position()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting position of parent frame: %w\", err)\n\t}\n\n\treturn &Rect{X: x + position.X, Y: y + position.Y, Width: width, Height: height}, nil\n}\n\n// translatePointToPage translates the point to the page's coordinates if the\n// point is relative to the parent frame.\nfunc (h *ElementHandle) translatePointToPage(apiCtx context.Context, point Position) (Position, error) {\n\th.logger.Debugf(\"ElementHandle:translatePointToPage\", \"point before translation: %v\", point)\n\n\tframe, err := h.ownerFrame(apiCtx)\n\tif err != nil {\n\t\treturn Position{}, fmt.Errorf(\"checking hit target at %v: %w\", point, err)\n\t}\n\n\tif frame == nil || frame.parentFrame == nil {\n\t\th.logger.Debugf(\"ElementHandle:translatePointToPage\", \"no parent frame\")\n\t\treturn point, nil","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/element_handle.go#L65-L101","documentation":"After computing the element's own quad in boundingBox(), k6 adds the owning frame's position via h.frame.position(). If that lookup fails (frame detached from the frame tree, page unavailable), the error is wrapped as 'getting position of parent frame'. It only affects elements inside iframes, since top-frame positions resolve trivially.","triggerScenarios":"Calling boundingBox()/click() on an element inside an iframe whose frame was detached (iframe removed from DOM, navigation inside the iframe) between the box-model call and the position lookup.","commonSituations":"Dynamic iframes (ads, embeds, OAuth popups) removed mid-interaction; iframe content navigating while k6 measures; reusing handles into frames that were closed.","solutions":["Re-acquire the frame and element right before interacting (fresh page.frameLocator(...)/locator query).","Wait for the iframe and its content to finish loading before measuring (frame.waitForNavigation or waiting on an element inside it).","Avoid interacting with iframes that scripts can remove; wait for stability or retry once.","If the iframe is optional, treat this error as a signal it is gone and skip the step."],"exampleFix":"// before\nconst frame = page.frame({ url: /oauth/ });\nconst btn = await frame.locator('#approve').getElementHandle();\nawait sleep(3000);                  // iframe gets removed meanwhile\nawait btn.click();                  // getting position of parent frame: ...\n\n// after\nconst btn = await page.frame({ url: /oauth/ }).locator('#approve').getElementHandle();\nawait btn.click();","handlingStrategy":"retry","validationCode":"// confirm the iframe (and its owner) still exists before measuring\nconst frame = page.frames().find((f) => f.url().includes('widget'));\nif (!frame) throw new Error('iframe gone before measurement');\nconst handle = await frame.locator(sel).getElementHandle();\nawait handle.boundingBox();","typeGuard":null,"tryCatchPattern":"try {\n  await handle.boundingBox();\n} catch (e) {\n  if (/getting position of parent frame/.test(String(e))) {\n    const f2 = page.frames().find((f) => f.url().includes('widget'));\n    if (!f2) return null;               // iframe legitimately removed\n    return await (await f2.locator(sel).getElementHandle()).boundingBox();\n  }\n  throw e;\n}","preventionTips":["Interact with iframe content through freshly resolved frame objects, not cached ones.","For removable iframes (ads, widgets), treat frame-loss errors as a skip condition, not a failure.","Wait for iframe content to finish loading before geometry or click operations."],"tags":["iframe","frame","element-handle","bounding-box","dom"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}