{"record":{"id":"0fde2bbc9d97d562","repo":"grafana/k6","slug":"missing-browser-context-s-current-context-is-s","errorCode":null,"errorMessage":"missing browser context %s, current context is %s","messagePattern":"missing browser context (.+?), current context is (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser.go","lineNumber":510,"sourceCode":"\t\t// We don't track targets of type \"browser\", \"other\" and \"devtools\",\n\t\t// so ignore if we don't recognize target.\n\t\treturn\n\t}\n\n\tb.pagesMu.Lock()\n\tdefer b.pagesMu.Unlock()\n\tif t, ok := b.pages[targetID]; ok {\n\t\tb.logger.Debugf(\"Browser:onDetachedFromTarget:deletePage\", \"sid:%v tid:%v\", ev.SessionID, targetID)\n\n\t\tdelete(b.pages, targetID)\n\t\tt.didClose()\n\t}\n}\n\nfunc (b *Browser) newPageInContext(id cdp.BrowserContextID) (*Page, error) {\n\tbc := b.getDefaultBrowserContextOrMatchedID(id)\n\tif bc.id != id {\n\t\treturn nil, fmt.Errorf(\"missing browser context %s, current context is %s\", id, bc.id)\n\t}\n\n\tctx, cancel := context.WithTimeout(b.vuCtx, b.browserOpts.Timeout)\n\tdefer cancel()\n\n\t// buffer of one is for sending the target ID whether an event handler\n\t// exists or not.\n\ttargetID := make(chan target.ID, 1)\n\n\twaitForPage, removeEventHandler := createWaitForEventHandler(\n\t\tctx,\n\t\tbc, // browser context will emit the following event:\n\t\t[]string{EventBrowserContextPage},\n\t\tfunc(e any) bool {\n\t\t\ttid := <-targetID\n\n\t\t\tb.logger.Debugf(\"Browser:newPageInContext:createWaitForEventHandler\",\n\t\t\t\t\"tid:%v ptid:%v bctxid:%v\", tid, e.(*Page).targetID, id) //nolint:forcetypeassert","sourceCodeStart":492,"sourceCodeEnd":528,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/browser.go#L492-L528","documentation":"Returned by newPageInContext (browser.go:510) when the browser context ID passed to browserContext.newPage() does not match the browser's current non-default context. getDefaultBrowserContextOrMatchedID falls back to the default context whenever b.context is nil (the context was disposed) or its ID differs, and the caller then detects the mismatch. It means the BrowserContext object you called newPage() on is stale — closed, or no longer the context the Browser is tracking (k6's Browser keeps a single b.context slot besides the default one).","triggerScenarios":"Calling newPage() after context.close() (disposeContext clears b.context, the lookup falls back to the default context and IDs differ); holding a reference to an older context after browser.newContext() created a newer one, then calling newPage() on the old reference.","commonSituations":"Reusing a context across setup/test/teardown after it was closed; helper functions caching the result of newContext(); porting Playwright tests that juggle several live contexts — the k6 browser module tracks only one non-default context at a time.","solutions":["Create a fresh context with browser.newContext() instead of reusing the closed/stale one","Call newPage() only while the context is open — before close()","Audit code for cached context references; pass pages, not contexts, to helpers","Restructure to a single newContext()…close() block per test instead of interleaving multiple contexts"],"exampleFix":"// before\nconst ctx = browser.newContext()\nconst p1 = ctx.newPage()\nawait ctx.close()\nconst p2 = ctx.newPage() // throws: missing browser context\n\n// after\nconst ctx = browser.newContext()\nconst p1 = ctx.newPage()\nawait ctx.close()\nconst ctx2 = browser.newContext() // fresh context\nconst p2 = ctx2.newPage()","handlingStrategy":"validation","validationCode":"function withContext(browser, fn) {\n  const ctx = browser.newContext()\n  try {\n    return fn(ctx)\n  } finally {\n    ctx.close()\n  }\n}\n// always create pages inside the context's live window","typeGuard":null,"tryCatchPattern":"try {\n  const page = ctx.newPage()\n} catch (e) {\n  if (/missing browser context/.test(String(e))) {\n    ctx = browser.newContext() // stale context — recreate and continue\n    page = ctx.newPage()\n  } else throw e\n}","preventionTips":["Never call newPage() after close(); null context references on close","Keep exactly one newContext()…close() lifecycle per test","Pass pages, not contexts, to helper functions"],"tags":["browser-context","stale-reference","lifecycle","new-page"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}