{"record":{"id":"34165ccd7e076b1c","repo":"grafana/k6","slug":"parsing-waitfornavigation-options-w","errorCode":null,"errorMessage":"parsing waitForNavigation options: %w","messagePattern":"parsing waitForNavigation options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame_options.go","lineNumber":730,"sourceCode":"\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"url\":\n\t\t\t\tvar val string\n\t\t\t\tswitch opts.Get(k).ExportType() {\n\t\t\t\tcase reflect.TypeFor[string]():\n\t\t\t\t\tval = fmt.Sprintf(\"'%s'\", opts.Get(k).String()) // Strings require quotes\n\t\t\t\tdefault: // JS Regex, CSS, numbers or booleans\n\t\t\t\t\tval = opts.Get(k).String() // No quotes\n\t\t\t\t}\n\n\t\t\t\to.URL = val\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\tcase \"waitUntil\":\n\t\t\t\tlifeCycle := opts.Get(k).String()\n\t\t\t\tif err := o.WaitUntil.UnmarshalText([]byte(lifeCycle)); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"parsing waitForNavigation options: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewFrameWaitForSelectorOptions(defaultTimeout time.Duration) *FrameWaitForSelectorOptions {\n\treturn &FrameWaitForSelectorOptions{\n\t\tState:   DOMElementStateVisible,\n\t\tStrict:  false,\n\t\tTimeout: defaultTimeout,\n\t}\n}\n\n// Parse parses the frame waitForSelector options.\nfunc (o *FrameWaitForSelectorOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame_options.go#L712-L748","documentation":"This error comes from the `waitUntil` branch of FrameWaitForNavigationOptions.Parse (frame_options.go:730). waitForNavigation validates its waitUntil via LifecycleEvent.UnmarshalText, which accepts only \"load\", \"domcontentloaded\" and \"networkidle\". Any other string aborts option parsing with this wrapped error before the navigation wait begins.","triggerScenarios":"frame.waitForNavigation({ waitUntil: 'load-complete' }) or page.waitForNavigation({ waitUntil: 'networkIdle' }); also passing a URL string as waitUntil by mixing up option keys. Note the same parser also builds o.URL from a `url` key and parses `timeout` in milliseconds.","commonSituations":"Scripts adapted from Playwright waitForURL/waitForNavigation examples that use different lifecycle names, or camelCase spellings like 'networkIdle' which k6 does not accept.","solutions":["Set waitUntil to \"load\", \"domcontentloaded\" or \"networkidle\" exactly","Keep timeout (milliseconds) and waitUntil keys separate; do not nest or rename them","If wrapping gotos in waitForNavigation, use the same lifecycle value on both calls for consistent behavior"],"exampleFix":"// before\nframe.waitForNavigation({ waitUntil: 'networkIdle', timeout: 5000 });\n\n// after\nframe.waitForNavigation({ waitUntil: 'networkidle', timeout: 5000 });","handlingStrategy":"validation","validationCode":"const WAIT_UNTIL = ['load', 'domcontentloaded', 'networkidle'];\nif (opts && opts.waitUntil !== undefined && !WAIT_UNTIL.includes(opts.waitUntil)) {\n  throw new Error(`invalid waitUntil: ${opts.waitUntil}`);\n}\nframe.waitForNavigation(opts);","typeGuard":"function isWaitUntil(v: unknown): v is 'load' | 'domcontentloaded' | 'networkidle' {\n  return v === 'load' || v === 'domcontentloaded' || v === 'networkidle';\n}","tryCatchPattern":null,"preventionTips":["Keep waitForNavigation's waitUntil in sync with the paired goto's waitUntil","Avoid camelCase spellings like 'networkIdle'"],"tags":["browser","options","waituntil","waitfornavigation","validation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}