grafana/k6 · error

parsing frame navigation options to %q: %w

Error message

parsing frame navigation options to %q: %w

What it means

The options object passed to frame.goto(url, opts) failed to parse (frame_mapping.go:207). FrameGotoOptions.Parse accepts 'referer', 'timeout', and 'waitUntil'; only an invalid waitUntil fails - it must be exactly one of 'load', 'domcontentloaded', or 'networkidle' (lifecycle.go UnmarshalText rejects anything else). The error message includes the target URL to help locate the failing call.

Source

Thrown at internal/js/modules/k6/browser/browser/frame_mapping.go:207

			ml := mapLocator(vu, f.GetByText(ptext, popts))
			return rt.ToValue(ml).ToObject(rt), nil
		},
		"getByTitle": func(title sobek.Value, opts sobek.Value) (*sobek.Object, error) {
			if k6common.IsNullish(title) {
				return nil, errors.New("missing required argument 'title'")
			}
			ptitle, popts := parseGetByBaseOptions(vu.Context(), title, false, opts)

			ml := mapLocator(vu, f.GetByTitle(ptitle, popts))
			return rt.ToValue(ml).ToObject(rt), nil
		},
		"goto": func(url string, opts sobek.Value) (*sobek.Promise, error) {
			gopts := common.NewFrameGotoOptions(
				f.Referrer(),
				f.NavigationTimeout(),
			)
			if err := gopts.Parse(vu.Context(), opts); err != nil {
				return nil, fmt.Errorf("parsing frame navigation options to %q: %w", url, err)
			}
			return promise(vu, func() (any, error) {
				resp, err := f.Goto(url, gopts)
				if err != nil {
					return nil, err //nolint:wrapcheck
				}

				return mapResponse(vu, resp), nil
			}), nil
		},
		"hover": func(selector string, opts sobek.Value) (*sobek.Promise, error) {
			popts := common.NewFrameHoverOptions(f.Timeout())
			if err := popts.Parse(vu.Context(), opts); err != nil {
				return nil, fmt.Errorf("parsing hover options: %w", err)
			}
			return promise(vu, func() (any, error) {
				return nil, f.Hover(selector, popts) //nolint:wrapcheck
			}), nil

View on GitHub (pinned to 93accf6570)

Solutions

  1. Use one of the exact lowercase strings: 'load', 'domcontentloaded', 'networkidle'
  2. Centralize the constant: const WAIT_UNTIL = Object.freeze({ LOAD: 'load', DOM: 'domcontentloaded', IDLE: 'networkidle' })
  3. Validate before the call: if (!['load','domcontentloaded','networkidle'].includes(opts.waitUntil)) throw ...

Example fix

// before
frame.goto('https://example.com', { waitUntil: 'networkIdle' });
// after
frame.goto('https://example.com', { waitUntil: 'networkidle' });
Defensive patterns

Strategy: validation

Validate before calling

const WAIT_UNTIL = new Set(['load', 'domcontentloaded', 'networkidle']);
if (opts?.waitUntil != null && !WAIT_UNTIL.has(opts.waitUntil)) {
  throw new Error(`waitUntil must be one of: ${[...WAIT_UNTIL].join(', ')}; got ${opts.waitUntil}`);
}

Type guard

function isWaitUntil(v) {
  return v == null || ['load', 'domcontentloaded', 'networkidle'].includes(v);
}

Try / catch

try {
  const resp = await frame.goto(url, opts);
} catch (e) {
  if (String(e.message).includes('parsing frame navigation options')) {
    throw new Error(`bad goto options for ${url}: check waitUntil spelling`);
  }
  throw e; // navigation timeout / network error
}

Prevention

When it happens

Trigger: frame.goto('https://example.com', { waitUntil: 'networkIdle' }) (camelCase), 'loaded', 'domcontentloaded ' (trailing space), or any unsupported value - UnmarshalText returns 'invalid lifecycle event: %q; must be one of: ...' which this wrapper prepends with 'parsing frame navigation options to "<url>":'.

Common situations: Porting from Playwright/Puppeteer where casing differs or extra events exist; option objects shared across page.goto and waitForLoadState with a typo; constants defined with different capitalization ('NETWORKIDLE').

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/d257d033b7880ef2. Report an issue: GitHub.