grafana/k6 · error

parsing hover options: %w

Error message

parsing hover options: %w

What it means

Thrown when locator.hover(opts) fails to parse options into FrameHoverOptions, which embeds ElementHandleBasePointerOptions. Unlike the lenient base parser, the pointer parser strictly exports the position key to map[string]float64 via rt.ExportTo, so hover({ position: ... }) with a non-object or non-numeric coordinates is a live error path: 'parsing hover options: <export error>'. Accepted keys: position {x: number, y: number}, trial boolean, timeout number ms, force boolean, noWaitAfter boolean.

Source

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

			}
			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 := common.NewFrameTypeOptions(lo.Timeout())
			if err := copts.Parse(vu.Context(), opts); 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 := common.NewFrameHoverOptions(lo.Timeout())
			if err := copts.Parse(vu.Context(), opts); 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 := common.NewFrameTapOptions(lo.DefaultTimeout())
			if err := copts.Parse(vu.Context(), opts); 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 := common.NewFrameDispatchEventOptions(lo.DefaultTimeout())
			if err := popts.Parse(vu.Context(), opts); err != nil {
				return nil, fmt.Errorf("parsing locator dispatch event options: %w", err)

View on GitHub (pinned to 93accf6570)

Solutions

  1. Omit position to hover the element center: hover({ timeout: 5000 })
  2. Or pass explicit numeric coordinates: hover({ position: { x: 100, y: 100 } })
  3. Coerce string coordinates to Number before passing
  4. Keep only supported keys: position, trial, force, noWaitAfter, timeout

Example fix

// before
await page.locator('#canvas').hover({ position: 'center' });

// after
await page.locator('#canvas').hover(); // center by default
// or
await page.locator('#canvas').hover({ position: { x: 100, y: 100 } });
Defensive patterns

Strategy: validation

Validate before calling

function assertHoverOpts(opts) {
  if (opts === null || opts === undefined) return;
  if (typeof opts !== 'object' || Array.isArray(opts)) {
    throw new TypeError('hover options must be a plain object');
  }
  if ('position' in opts && opts.position !== undefined) {
    const p = opts.position;
    if (typeof p !== 'object' || p === null || Array.isArray(p)) {
      throw new TypeError("hover position must be { x: number, y: number }; strings like 'center' are not supported");
    }
    if (typeof p.x !== 'number' || typeof p.y !== 'number') {
      throw new TypeError('hover position x and y must be numbers');
    }
  }
}

Type guard

function isPointerPosition(v) {
  return typeof v === 'object' && v !== null && !Array.isArray(v) &&
    typeof v.x === 'number' && Number.isFinite(v.x) &&
    typeof v.y === 'number' && Number.isFinite(v.y);
}

Try / catch

try {
  await locator.hover(opts);
} catch (e) {
  if (/parsing hover options/.test(String(e.message))) {
    throw new Error(`Bad hover options (check position: {x,y} numbers only): ${e.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: hover({ position: 'center' }) — position must be explicit coordinates, the 'center' string is not supported; hover({ position: { x: '100', y: 100 } }) — string coordinates; hover({ position: [100, 100] }) — array instead of {x, y} object.

Common situations: Porting Playwright examples where 'center' is sometimes documented as behavior rather than a literal; data-driven coordinates arriving as strings from JSON fixtures; assuming array tuples work as positions.

Related errors


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