grafana/k6 · error

parsing hover options

Error message

parsing hover options: %w

What it means

Thrown synchronously when the options argument to locator.hover(opts) fails to parse. The mapping (locator_mapping.go:397-401) builds common.FrameHoverOptions and wraps Parse failures as "parsing hover options: %w". Parse runs ElementHandleHoverOptions.Parse (element_handle_options.go:377-395): after the base keys, it exports "position" to map[string]float64 and "modifiers" to []string — these two ExportTo conversions are the only value-level failures, e.g. position: {x:'10'} with string coordinates or modifiers: 'Shift' as a bare string.

Solutions

  1. Pass position as { x: <number>, y: <number> } relative to the element's top-left, with Number()-converted values
  2. Pass modifiers as an array of strings from 'Alt', 'Control', 'Meta', 'Shift'
  3. Keep other keys (force, noWaitAfter, timeout, trial, strict) as plain data
  4. try/catch the call and validate position/modifiers beforehand when values are computed

Example fix

// before
const box = await locator.boundingBox();
await locator.hover({ position: { x: `${box.width}/2`, y: box.height / 2 } }); // template string

// after
const box = await locator.boundingBox();
await locator.hover({ position: { x: box.width / 2, y: box.height / 2 } });
Defensive patterns

Strategy: validation

Validate before calling

function assertHoverOptions(opts) {
  if (opts == null) return;
  if (typeof opts !== 'object' || Array.isArray(opts)) throw new TypeError('hover options must be an object');
  if (opts.position != null) {
    const p = opts.position;
    if (typeof p !== 'object' || !Number.isFinite(p.x) || !Number.isFinite(p.y))
      throw new TypeError(`position must be { x: number, y: number }, got ${JSON.stringify(p)}`);
  }
  if (opts.modifiers != null) {
    if (!Array.isArray(opts.modifiers) || opts.modifiers.some(m => typeof m !== 'string'))
      throw new TypeError('modifiers must be an array of strings');
  }
}
assertHoverOptions(opts);
await locator.hover(opts);

Type guard

function isHoverOptions(o) {
  if (o == null) return true;
  if (typeof o !== 'object') return false;
  const pOk = o.position === undefined ||
    (typeof o.position === 'object' && Number.isFinite(o.position.x) && Number.isFinite(o.position.y));
  const mOk = o.modifiers === undefined ||
    (Array.isArray(o.modifiers) && o.modifiers.every(m => typeof m === 'string'));
  return pOk && mOk;
}

Try / catch

try { await locator.hover(opts); } catch (e) { if (String(e).includes('parsing hover options')) throw new Error(`bad hover position/modifiers: ${JSON.stringify(opts)}`); throw e; }

Prevention

When it happens

Trigger: locator.hover({ position: { x: '10', y: 20 } }) with string coordinates; position given as a string or number instead of {x,y}; modifiers: 'Shift' instead of ['Shift']; modifiers: [1,2]; plus throwing getters/Proxy traps on any key.

Common situations: Hovering at coordinates read from data attributes or boundingBox math that produce strings; passing Playwright-style modifiers as a string; computed position variables that end up undefined/null-shaped; instrumentation Proxies over options.

Related errors


AI-assisted analysis of grafana/k6@8d06114777 (2026-09-14). Data as JSON: /api/errors/3e1b5569a553c214. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/browser/locator_mapping.go:401

			}
			return promise(vu, func() (any, error) {
				return nil, lo.PressSequentially(text, copts) //nolint:wrapcheck
			}), nil
		},

		"type": func(text string, opts sobek.Value) (*sobek.Promise, error) {
			copts, err := parseFrameTypeOptions(rt, opts, lo.Timeout())
			if err != nil {
				return nil, fmt.Errorf("parsing type options: %w", err)
			}
			return promise(vu, func() (any, error) {
				return nil, lo.Type(text, copts) //nolint:wrapcheck
			}), nil
		},
		"hover": func(opts sobek.Value) (*sobek.Promise, error) {
			copts, err := parseFrameHoverOptions(rt, opts, lo.Timeout())
			if err != nil {
				return nil, fmt.Errorf("parsing hover options: %w", err)
			}
			return promise(vu, func() (any, error) {
				return nil, lo.Hover(copts) //nolint:wrapcheck
			}), nil
		},
		"tap": func(opts sobek.Value) (*sobek.Promise, error) {
			copts, err := parseFrameTapOptions(rt, opts, lo.DefaultTimeout())
			if err != nil {
				return nil, fmt.Errorf("parsing locator tap options: %w", err)
			}
			return promise(vu, func() (any, error) {
				return nil, lo.Tap(copts) //nolint:wrapcheck
			}), nil
		},
		"dispatchEvent": func(typ string, eventInit, opts sobek.Value) (*sobek.Promise, error) {
			popts, err := parseFrameDispatchEventOptions(rt, opts, lo.DefaultTimeout())
			if err != nil {
				return nil, fmt.Errorf("parsing locator dispatch event options: %w", err)

View on GitHub (pinned to 8d06114777)