{"record":{"id":"6a0073a9e9e1fd21","repo":"grafana/k6","slug":"parsing-frame-wait-for-navigation-options-w","errorCode":null,"errorMessage":"parsing frame wait for navigation options: %w","messagePattern":"parsing frame wait for navigation options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/page_mapping.go","lineNumber":992,"sourceCode":"\t}\n\n\tpurl := parseStringOrRegex(url, false)\n\ttq, ctx, stop := newTaskQueue(vu)\n\n\treturn promise(vu, func() (result any, reason error) {\n\t\tdefer stop()\n\t\treturn nil, target.WaitForURL(purl, popts, newRegExMatcher(ctx, vu, tq))\n\t}), nil\n}\n\nfunc mapWaitForNavigation(vu moduleVU, target interface {\n\tTimeout() time.Duration\n\tWaitForNavigation(*common.FrameWaitForNavigationOptions, common.RegExMatcher) (*common.Response, error)\n}, opts sobek.Value,\n) (*sobek.Promise, error) {\n\tpopts := common.NewFrameWaitForNavigationOptions(target.Timeout())\n\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing frame wait for navigation options: %w\", err)\n\t}\n\n\t// Only use task queue and RegExMatcher if a URL is specified.\n\trm, stop := func() (common.RegExMatcher, func()) {\n\t\tif popts.URL == \"\" {\n\t\t\treturn nil, func() {}\n\t\t}\n\t\ttq, ctx, stop := newTaskQueue(vu)\n\t\treturn newRegExMatcher(ctx, vu, tq), stop\n\t}()\n\n\treturn promise(vu, func() (any, error) {\n\t\tdefer stop()\n\n\t\tresp, err := target.WaitForNavigation(popts, rm)\n\t\tif err != nil {\n\t\t\treturn nil, err //nolint:wrapcheck\n\t\t}","sourceCodeStart":974,"sourceCodeEnd":1010,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/js/modules/k6/browser/browser/page_mapping.go#L974-L1010","documentation":"Thrown by page.waitForNavigation(opts) (and the frame variant) when FrameWaitForNavigationOptions.Parse rejects the options object. The parser validates keys like 'timeout', 'waitUntil' and 'url'; unknown keys or invalid values (bad waitUntil string, non-numeric timeout) are wrapped in this message.","triggerScenarios":"page.waitForNavigation({ waitUntil: 'networkidle2' }) (Puppeteer value); passing unknown keys; { url: 123 } where a string/regex is expected; string durations like { timeout: '10s' }.","commonSituations":"Migrating Puppeteer scripts (networkidle0/networkidle2 values); assuming Playwright's extra navigation options exist; racing navigation patterns where users add ad-hoc keys.","solutions":["Use { timeout: <ms>, waitUntil: 'load' | 'domcontentloaded' | 'networkidle', url: <string|RegExp> } only.","Replace Puppeteer waitUntil values: 'networkidle0'/'networkidle2' → 'networkidle'.","Trigger the navigation and the wait together (click then waitForNavigation in a Promise.all) so options stay minimal.","Prefer page.waitForURL(url, opts) for URL-targeted waits."],"exampleFix":"// before\nawait Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle2' }), page.click('a.next') ]);\n\n// after\nawait Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle' }), page.click('a.next') ]);","handlingStrategy":"validation","validationCode":"const opts = { timeout: 10000, waitUntil: 'load' };\nif (!['load','domcontentloaded','networkidle'].includes(opts.waitUntil)) throw new Error(`invalid waitUntil '${opts.waitUntil}'`);\nif (opts.url !== undefined && typeof opts.url !== 'string' && !(opts.url instanceof RegExp)) throw new Error('url must be string or RegExp');\nawait Promise.all([ page.waitForNavigation(opts), page.click('a') ]);","typeGuard":"const isNavOpts = (o) => o == null || (typeof o === 'object' && Object.keys(o).every(k => ['timeout','waitUntil','url'].includes(k)) && [undefined,'load','domcontentloaded','networkidle'].includes(o.waitUntil));","tryCatchPattern":"try { await page.waitForNavigation(opts); } catch (e) { if (e.message.includes('parsing frame wait for navigation options')) { /* normalize waitUntil and retry */ } throw e; }","preventionTips":["Map Puppeteer waitUntil values ('networkidle0'/'networkidle2' → 'networkidle') during migrations.","Keep navigation options minimal: usually just waitUntil.","Always race waitForNavigation with the trigger action (Promise.all) so options stay small."],"tags":["k6","browser","page","waitfornavigation","options","argument-validation"],"backgroundTag":"invalid-options-object","analyzedSha":"01ffac6f245854c1b8adc6a69857c76a15f90022","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}