{"record":{"id":"8539394ca6d0721a","repo":"grafana/k6","slug":"browser-is-closing","errorCode":null,"errorMessage":"browser is closing","messagePattern":"browser is closing","errorType":"exception","errorClass":"errBrowserClosing","httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser.go","lineNumber":369,"sourceCode":"\t\t}\n\n\t\tdetachSession(session)\n\n\t\treturn nil\n\t}\n\n\t// Emit the page event only for pages, not for background pages.\n\t// Background pages are created by extensions.\n\tif isPage {\n\t\tbrowserCtx.emit(EventBrowserContextPage, p)\n\t}\n\n\treturn nil\n}\n\n// errBrowserClosing is returned when a page attachment\n// is rejected because the browser has started closing.\nvar errBrowserClosing = errors.New(\"browser is closing\")\n\n// attachNewPage checks whether the browser is closing and, if not, attaches\n// the page. Returns errBrowserClosing if the browser is shutting down.\nfunc (b *Browser) attachNewPage(p *Page, ev *target.EventAttachedToTarget) error {\n\ttargetPage := ev.TargetInfo\n\n\tattachPage := func() error {\n\t\tb.pagesMu.Lock()\n\t\tdefer b.pagesMu.Unlock()\n\n\t\tif b.closing.Load() {\n\t\t\treturn errBrowserClosing\n\t\t}\n\n\t\tb.logger.Debugf(\n\t\t\t\"Browser:attachNewPage:addTarget\",\n\t\t\t\"sid:%v tid:%v pageType:%s\",\n\t\t\tev.SessionID, targetPage.TargetID, targetPage.Type,","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/grafana/k6/blob/94169daab29df52c1ed2ee0549657a577666b855/internal/js/modules/k6/browser/common/browser.go#L351-L387","documentation":"The Browser type keeps an atomic closing flag set by Close() and by context teardown. When a new target (page/popup) tries to attach after closing has started, attachNewPage rejects it with errBrowserClosing (internal/js/modules/k6/browser/common/browser.go:368). The guard prevents mutating a browser that is already shutting down; the error usually surfaces as a race between teardown and a late CDP Target.attachedToTarget event.","triggerScenarios":"A click/navigation opens a popup at the same moment browser.close() runs at the end of the default function; calling browser.newPage()/newContext() after close(); the scenario timeout canceling the context while a target-attached event is in flight; reusing a browser handle across iterations after it was closed.","commonSituations":"Popup-heavy tests where the last interaction triggers a new tab during teardown; close() in a finally block racing in-flight CDP events; shared browser instances across VUs; tight test durations that cut off page creation.","solutions":["Await every action that can open a page before closing: const popup = await page.waitForEvent('popup'); await popup.close(); then browser.close() last","If a popup may appear, handle it explicitly (waitForEvent('popup')) instead of letting it race teardown","During teardown, catch and ignore this specific error when the page is no longer needed","Extend the scenario/iteration timeout if k6 is canceling mid-navigation"],"exampleFix":"// before\nawait page.click('#opens-popup');\nbrowser.close(); // popup attach still in flight -> \"browser is closing\"\n\n// after\nconst popup = await page.waitForEvent('popup');\nawait popup.close();\nbrowser.close();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// tolerate the teardown race when the extra page is no longer needed\ntry {\n  const page = await browser.newPage();\n} catch (e) {\n  if (!String(e?.message || e).includes('browser is closing')) throw e;\n  // shutting down — skip page setup\n}","preventionTips":["Make browser.close() the last statement and await every navigation/popup before it","Handle popups explicitly with page.waitForEvent('popup') instead of letting them race teardown","Never reuse a browser instance after close(); create it per iteration via the module API","Give scenarios enough duration that page creation is not canceled mid-flight"],"tags":["browser","lifecycle","race-condition","popup","teardown"],"backgroundTag":"use-after-close","analyzedSha":"94169daab29df52c1ed2ee0549657a577666b855","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}