{"record":{"id":"185a1a5fc9941dc1","repo":"grafana/k6","slug":"closing-a-page-w","errorCode":null,"errorMessage":"closing a page: %w","messagePattern":"closing a page: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/js/modules/k6/browser/common/page.go","lineNumber":1021,"sourceCode":"\n\t\tadd := runtime.RemoveBinding(webVitalBinding)\n\t\tif err := add.Do(cdp.WithExecutor(teardownTimeoutCtx, p.session)); err != nil {\n\t\t\t// continue so that we can shutdown the page even if we fail to remove the binding.\n\t\t\tcloseErrs = append(closeErrs, fmt.Errorf(\"internal error while removing binding from page: %w\", err))\n\t\t}\n\n\t\terr := target.CloseTarget(p.targetID).Do(cdp.WithExecutor(teardownTimeoutCtx, p.session))\n\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t// When a close target command is sent to the browser via CDP,\n\t\t\t// the browser will start to cleanup and the first thing it\n\t\t\t// will do is return a target.EventDetachedFromTarget, which in\n\t\t\t// our implementation will close the session connection (this\n\t\t\t// does not close the CDP websocket, just removes the session\n\t\t\t// so no other CDP calls can be made with the session ID).\n\t\t\t// This can result in the session's context being closed while\n\t\t\t// we're waiting for the response to come back from the browser\n\t\t\t// for this current command (it's racey).\n\t\t\tcloseErrs = append(closeErrs, fmt.Errorf(\"closing a page: %w\", err))\n\t\t}\n\n\t\t// Start the teardown of the page's resources (FrameSessions, NetworkManagers, etc)\n\t\t// and wait for them to finish their teardown. This allows for a graceful cleanup\n\t\t// of resources and ensures that all events are processed before the page is closed.\n\t\tp.cancelCtx()\n\t\tp.waitForFrameSessions()\n\n\t\tif len(closeErrs) > 0 {\n\t\t\tp.closeErr = spanRecordError(span, errors.Join(closeErrs...))\n\t\t}\n\t})\n\n\treturn p.closeErr\n}\n\n// Content returns the HTML content of the page.\nfunc (p *Page) Content() (string, error) {","sourceCodeStart":1003,"sourceCodeEnd":1039,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/page.go#L1003-L1039","documentation":"Page.Close sends target.CloseTarget to the browser; if that command fails with anything other than context.Canceled, this error is recorded. context.Canceled is explicitly tolerated because closing a target races with session teardown, but other failures (target not found, browser connection dead) surface here.","triggerScenarios":"page.close() when the tab was already closed (manually or by the site), the browser process crashed, or the DevTools websocket dropped. The close proceeds with local teardown regardless, and the error is joined into page.close()'s return.","commonSituations":"Site JavaScript (window.close, target=_blank flows) closing the tab first; browser crash earlier in the run; closing pages in the wrong order relative to browser.close(); reusing a page handle after its tab died.","solutions":["Wrap page.close() in a catch when the tab's lifetime is not fully under your control","Check page.isClosed() before explicit close","Verify the browser is still running before teardown if crashes are suspected","Only escalate the error if subsequent operations on that browser still fail"],"exampleFix":"// before\nawait page.close(); // throws if tab already gone\n\n// after\ntry {\n  await page.close();\n} catch (e) {\n  if (!/closing a page/.test(e.message)) throw e;\n  console.warn('page already closed elsewhere');\n}","handlingStrategy":"validation","validationCode":"if (!page.isClosed()) { await page.close(); }","typeGuard":null,"tryCatchPattern":"try {\n  await page.close();\n} catch (e) {\n  if (!/closing a page/.test(e.message)) throw e; // tab was likely already gone\n}","preventionTips":["Tolerate close failures when the tab's lifetime is not fully script-controlled","Close pages before browser.close() in a strict order"],"tags":["browser","page-close","cdp","target","teardown"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}