{"record":{"id":"ffaaf83cd4e70882","repo":"grafana/k6","slug":"waitforevent-timed-out-after-v","errorCode":null,"errorMessage":"waitForEvent timed out after %v","messagePattern":"waitForEvent timed out after (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser_context.go","lineNumber":383,"sourceCode":"\t}\n\n\tevCancelCtx, evCancelFn := context.WithCancel(b.ctx)\n\tdefer evCancelFn() // This will remove the event handler once we return from here.\n\n\tchEvHandler := make(chan Event)\n\tch := make(chan any)\n\terrCh := make(chan error)\n\n\tgo b.runWaitForEventHandler(evCancelCtx, chEvHandler, predicateFn, ch, errCh)\n\n\tb.on(evCancelCtx, []string{EventBrowserContextPage}, chEvHandler)\n\n\tselect {\n\tcase <-b.ctx.Done():\n\t\treturn nil, ContextErr(b.ctx) //nolint:wrapcheck\n\tcase <-time.After(timeout):\n\t\tb.logger.Debugf(\"BrowserContext:WaitForEvent:timeout\", \"bctxid:%v event:%q\", b.id, event)\n\t\treturn nil, fmt.Errorf(\"waitForEvent timed out after %v\", timeout)\n\tcase evData := <-ch:\n\t\tb.logger.Debugf(\"BrowserContext:WaitForEvent:evData\", \"bctxid:%v event:%q\", b.id, event)\n\t\treturn evData, nil\n\tcase err := <-errCh:\n\t\tb.logger.Debugf(\"BrowserContext:WaitForEvent:err\", \"bctxid:%v event:%q, err:%v\", b.id, event, err)\n\t\treturn nil, err\n\t}\n}\n\n// runWaitForEventHandler can work with a nil predicateFn. If predicateFn is\n// nil it will return the response straight away.\nfunc (b *BrowserContext) runWaitForEventHandler(\n\tctx context.Context,\n\tchEvHandler chan Event, predicateFn func(p *Page) (bool, error),\n\tout chan<- any, errOut chan<- error,\n) {\n\tb.logger.Debugf(\"BrowserContext:runWaitForEventHandler:go():starts\", \"bctxid:%v\", b.id)\n\tdefer b.logger.Debugf(\"BrowserContext:runWaitForEventHandler:go():returns\", \"bctxid:%v\", b.id)","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/browser_context.go#L365-L401","documentation":"Thrown by BrowserContext.waitForEvent when no new page event satisfies the wait within the given timeout. The implementation selects on the context cancellation, a time.After(timeout) timer, the event channel, and the error channel; if the timer fires first you get 'waitForEvent timed out after <duration>'. Unlike the other branches, this is a plain timeout condition, not a wrapped lower-level failure.","triggerScenarios":"Calling browserContext.waitForEvent('page', { timeout }) when no new page/tab is opened in the context during the timeout window, or when the predicate passed as the second argument never returns true for the pages that do open. Note waitForEvent does not itself open anything: your script must trigger the new page (e.g. click a link with target=_blank).","commonSituations":"Forgetting to perform the action that opens the new tab after registering the wait; a popup blocked by the browser (popup blocker, permission denied); the triggering click failing silently; timeout too short for a slow page under load; predicate conditions that never match.","solutions":["Perform the action that opens the new page after calling waitForEvent (waitForEvent resolves concurrently; the click/trigger must actually run), e.g. click the target=_blank link next.","Pass a larger timeout in the options/predicate argument, e.g. waitForEvent('page', { timeout: 60_000 }).","Debug why no page appears: check that popups are allowed, the selector clicked is correct, and look at debug logs for EventBrowserContextPage entries.","If a predicate is used, verify it can return true (e.g. don't assert a URL the page never has)."],"exampleFix":"// before\nconst pagePromise = ctx.waitForEvent('page');\n// nothing opens a new page -> timeout\n\n// after\nconst pagePromise = ctx.waitForEvent('page', { timeout: 30000 });\nawait page.click('a[target=\"_blank\"]'); // triggers the new tab\nconst newPage = await pagePromise;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const newPage = await context.waitForEvent('page', { timeout: 30000 });\n} catch (e) {\n  if (e.message.includes('timed out')) {\n    // no new page appeared: check the trigger action, popup settings, or raise the timeout\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always perform the action that opens the new page after registering the wait.","Set an explicit timeout sized to the app's worst-case page-open time.","Verify popups are permitted in the browser context when the new page comes from target=_blank or window.open.","Keep predicates permissive so the wait doesn't depend on exact page state."],"tags":["timeout","events","waitfor","browser-context"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}