{"record":{"id":"6ce2861842984f5e","repo":"grafana/k6","slug":"parsing-waitforurl-options-w-6ce286","errorCode":null,"errorMessage":"parsing waitForURL options: %w","messagePattern":"parsing waitForURL options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame_options.go","lineNumber":826,"sourceCode":"\treturn &FrameWaitForURLOptions{\n\t\tTimeout:   defaultTimeout,\n\t\tWaitUntil: LifecycleEventLoad,\n\t}\n}\n\n// Parse parses the frame waitForURL options.\nfunc (o *FrameWaitForURLOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\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 waitForURL options: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":808,"sourceCodeEnd":833,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame_options.go#L808-L833","documentation":"FrameWaitForURLOptions.Parse (frame_options.go:826) validates the `waitUntil` option of frame.waitForURL()/page.waitForURL() with LifecycleEvent.UnmarshalText. Only \"load\", \"domcontentloaded\" and \"networkidle\" are legal; any other value fails parsing with this wrapped error and the wait is never started.","triggerScenarios":"page.waitForURL('https://example.com/done', { waitUntil: 'idle' }) or { waitUntil: 'Load' }. The parser only reads the `timeout` (ms) and `waitUntil` keys; the URL itself is a positional argument, not an option key.","commonSituations":"Copying waitUntil spellings from other tooling or docs, or sharing an options object between waitForURL and custom code that uses different lifecycle vocabulary.","solutions":["Pass \"load\", \"domcontentloaded\" or \"networkidle\" exactly as waitUntil","Put the URL pattern in the first argument, not inside the options object","Reuse a single validated options constant across all navigation-wait calls in the script"],"exampleFix":"// before\npage.waitForURL('**/dashboard', { waitUntil: 'loaded' });\n\n// after\npage.waitForURL('**/dashboard', { waitUntil: 'load' });","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}\npage.waitForURL(pattern, opts);","typeGuard":"function isWaitUntil(v: unknown): v is 'load' | 'domcontentloaded' | 'networkidle' {\n  return typeof v === 'string' && ['load', 'domcontentloaded', 'networkidle'].includes(v);\n}","tryCatchPattern":null,"preventionTips":["The URL/pattern is the first argument, options only carry timeout/waitUntil","Reuse one validated options object across goto/waitForNavigation/waitForURL"],"tags":["browser","options","waituntil","waitforurl","validation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}