{"record":{"id":"eb3dc4042458a814","repo":"grafana/k6","slug":"no-frame-found-for-node-w","errorCode":null,"errorMessage":"no frame found for node: %w","messagePattern":"no frame found for node: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/element_handle.go","lineNumber":1159,"sourceCode":"\t}\n\tdefer func() {\n\t\tif err := documentHandle.Dispose(); err != nil {\n\t\t\terr = fmt.Errorf(\"disposing document element: %w\", err)\n\t\t\trerr = errors.Join(err, rerr)\n\t\t}\n\t}()\n\n\tif documentHandle.remoteObject.ObjectID == \"\" {\n\t\treturn nil, err\n\t}\n\n\tvar node *cdp.Node\n\taction := dom.DescribeNode().WithObjectID(documentHandle.remoteObject.ObjectID)\n\tif node, err = action.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting node in frame: %w\", err)\n\t}\n\tif node == nil || node.FrameID == \"\" {\n\t\treturn nil, fmt.Errorf(\"no frame found for node: %w\", err)\n\t}\n\n\tframe, ok := h.frame.manager.getFrameByID(node.FrameID)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"no frame found for id %s\", node.FrameID)\n\t}\n\n\treturn frame, nil\n}\n\n// Press scrolls element into view and presses the given keys.\nfunc (h *ElementHandle) Press(key string, opts *ElementHandlePressOptions) error {\n\tpress := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.press(apiCtx, key, KeyboardOptions{})\n\t}\n\tpressAction := h.newAction(\n\t\t[]string{}, press, false, withRetry, opts.NoWaitAfter, opts.Timeout,\n\t)","sourceCodeStart":1141,"sourceCodeEnd":1177,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/element_handle.go#L1141-L1177","documentation":"OwnerFrame() got a successful DOM.describeNode response but the returned node is nil or has an empty FrameID (element_handle.go:1159). Note the message wraps the already-nil err, so it renders as 'no frame found for node: %!w(<nil>)' — a formatting quirk that tells you this is a detached/frame-less node, not a transport failure.","triggerScenarios":"The element is detached from the document (stale handle), belongs to a destroyed document, or DescribeNode returns a node that has no frame association (e.g., a document node in a torn-down context).","commonSituations":"Keeping an ElementHandle across a page navigation or SPA re-render and then calling something that needs the owner frame; iframe content removed between query and use.","solutions":["Treat the handle as stale: re-run the query that produced it and retry","Wait for a stable state (waitForLoadState / waitForSelector visible) before the call","If you control the code path, check handle validity (isVisible) before frame-dependent operations","Report the %!w(<nil>) formatting upstream — the wrapped err is always nil here"],"exampleFix":"// before\nconst el = page.$('button');\nawait page.goto(page.url()); // DOM replaced, el is stale\nel.click(); // owner-frame resolution may fail\n// after\nawait page.goto(page.url());\nconst el = await page.waitForSelector('button', { state: 'visible' });\nel.click();","handlingStrategy":"validation","validationCode":"// Guard against stale handles before the call\nif (!(await el.isVisible())) {\n  el = await page.waitForSelector(sel, { state: 'visible' });\n}","typeGuard":null,"tryCatchPattern":"try { await el.click(); }\ncatch (e) { if (/no frame found for node/.test(e.message)) { el = await page.waitForSelector(sel); await el.click(); } else throw e; }","preventionTips":["Treat this message as 'stale/detached element' — the wrapped error is always nil","Refresh handles after DOM replacements","Wait for selector visible state before acting"],"tags":["browser","stale-handle","cdp","navigation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}