{"record":{"id":"a9dd6cdf56ba65f9","repo":"grafana/k6","slug":"attaching-new-page-w","errorCode":null,"errorMessage":"attaching new page: %w","messagePattern":"attaching new page: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser.go","lineNumber":337,"sourceCode":"\t\tb.pagesMu.RUnlock()\n\t}\n\tp, err := NewPage(b.vuCtx, session, browserCtx, targetPage.TargetID, opener, isPage, b.logger)\n\tif err != nil && b.isPageAttachmentErrorIgnorable(ev, session, err) {\n\t\tif b.closing.Load() {\n\t\t\tb.logger.Debugf(\"Browser:onAttachedToTarget\", \"new page failed; browser is closing: sid:%v\", ev.SessionID)\n\t\t\tdetachSession(b.browserCtx, session)\n\t\t}\n\t\treturn nil // Ignore this page.\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating a new %s: %w\", targetPage.Type, err)\n\t}\n\n\t// This prevents a race where Close() sets closing and snapshots\n\t// pages, but a new page is inserted outside that snapshot.\n\tif err := b.attachNewPage(p, ev); err != nil {\n\t\tif !errors.Is(err, errBrowserClosing) {\n\t\t\treturn fmt.Errorf(\"attaching new page: %w\", err)\n\t\t}\n\n\t\tb.logger.Debugf(\n\t\t\t\"Browser:onAttachedToTarget\",\n\t\t\t\"rejected page attachment; browser is closing: sid:%v tid:%v\",\n\t\t\tev.SessionID, ev.TargetInfo.TargetID,\n\t\t)\n\t\tif closeErr := p.Close(); closeErr != nil {\n\t\t\tb.logger.Debugf(\n\t\t\t\t\"Browser:onAttachedToTarget\",\n\t\t\t\t\"closing rejected page: %v\", closeErr,\n\t\t\t)\n\t\t}\n\n\t\tdetachSession(b.browserCtx, session)\n\n\t\treturn nil\n\t}","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/browser.go#L319-L355","documentation":"Thrown by Browser.onAttachedToTarget (internal/js/modules/k6/browser/common/browser.go:337) while handling a CDP Target.attachedToTarget event. After k6 builds the internal Page object for a new target, it registers the page via attachNewPage; if registration fails with anything other than the sentinel errBrowserClosing, the failure is wrapped as 'attaching new page: %w'. In the current implementation attachNewPage only ever returns errBrowserClosing or nil, so this message is a defensive guard against an internal race/invariant failure; when it fires it propagates through initEvents, which panics the VU with 'browser is attaching to target'.","triggerScenarios":"A new target (page, popup, iframe) attaches at the exact moment browser.close() runs or the CDP connection is dropping, and the attach fails for a reason other than the closing flag — e.g. closing the browser while a page under test opens popups, or chromium crashing mid-attach.","commonSituations":"Calling browser.close() (or ending the k6 iteration) while pages/popups are still being created; chromium dying under memory pressure during navigation; races between the browser closing flag and the page map in older k6 browser module versions.","solutions":["Order the script so all page/popup work completes before browser.close(); never close while targets may still attach","Retry the page-creating action once after confirming the browser is still alive (check K6_BROWSER_LOG=debug output)","Capture debug logs (K6_BROWSER_LOG=debug) to get the sid/tid of the rejected target and the wrapped error","Upgrade k6 — attach/closing race handling in the browser module has changed across releases; if it persists, report the debug log to k6"],"exampleFix":"// before\npage.goto('https://site-with-popups.example') // popups still attaching\nbrowser.close() // races with attach\n\n// after\nawait page.goto('https://site-with-popups.example')\nawait page.waitForLoadState()\n// popups settled, now close\nawait browser.close()","handlingStrategy":"retry","validationCode":"// avoid closing while targets may attach: sequence the script\n// const page = ctx.newPage(); await page.goto(url); await settle(); await browser.close();","typeGuard":null,"tryCatchPattern":"try {\n  const page = ctx.newPage()\n} catch (e) {\n  if (/attaching new page|browser is closing/.test(String(e))) {\n    // transient shutdown race — only retry if the browser is still usable\n    throw e\n  }\n  throw e\n}","preventionTips":["Complete all page and popup work before browser.close()","Treat 'attaching new page' as a shutdown race: log and end the iteration, do not loop-retry against a closing browser","Enable K6_BROWSER_LOG=debug during test authoring so attach races are visible"],"tags":["browser","cdp","race-condition","lifecycle","popup"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}