grafana/k6 · error
parsing locator tap options
Error message
parsing locator tap options: %w
What it means
Thrown synchronously when the options argument to locator.tap(opts) fails to parse. The mapping (locator_mapping.go:406-410) builds common.FrameTapOptions — notably seeded with lo.DefaultTimeout() rather than the locator timeout — and wraps Parse failures as "parsing locator tap options: %w". Parse (frame_options.go:571-592) runs the pointer base (position exported to map[string]float64, trial, force, noWaitAfter, timeout) then exports "modifiers" to []string; those ExportTo conversions are the realistic failure points.
Solutions
- Pass position as { x: <number>, y: <number> } with numeric values relative to the element's top-left corner
- Pass modifiers as an array of modifier key strings, e.g. ['Alt', 'Shift']
- Coerce computed coordinates with Number() before building the options object
- Validate the options shape before calling tap when coordinates come from external data; try/catch otherwise
Example fix
// before
const p = await el.getAttribute('data-tap'); // "12,34"
const [x, y] = p.split(',');
await locator.tap({ position: { x, y } }); // strings -> parse error
// after
const [x, y] = p.split(',').map(Number);
await locator.tap({ position: { x, y } }); Defensive patterns
Strategy: validation
Validate before calling
function assertTapOptions(opts) {
if (opts == null) return;
if (typeof opts !== 'object' || Array.isArray(opts)) throw new TypeError('tap 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');
}
}
assertTapOptions(opts);
await locator.tap(opts); Type guard
function isTapOptions(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.tap(opts); } catch (e) { if (String(e).includes('parsing locator tap options')) throw new Error(`bad tap position/modifiers: ${JSON.stringify(opts)}`); throw e; } Prevention
- Convert tap coordinates from external sources with Number() before the call
- Pass modifiers as an array of strings like ['Alt','Shift']
- Remember tap uses the browser default timeout unless you pass timeout explicitly
- Validate computed positions when data comes from attributes or APIs
When it happens
Trigger: locator.tap({ position: 'center' }) or position: { x: '10', y: 20 } with string coordinates; position that is not an object; modifiers: 'Shift' instead of an array; modifiers containing numbers; throwing getters or Proxy traps on options.
Common situations: Mobile emulation tests tapping at coordinates computed from element bounding boxes where values become strings; passing Playwright-style option objects with a bare-string modifiers; helper functions that conditionally build position and sometimes pass undefined fields.
Related errors
- parsing hover options
- parsing double click options
- parsing element tap options
- parsing hover options
- parsing hover options
AI-assisted analysis of grafana/k6@8d06114777 (2026-09-14).
Data as JSON: /api/errors/c341ce3754dcb788.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/browser/locator_mapping.go:410
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)
}
return promise(vu, func() (any, error) {
return nil, lo.DispatchEvent(typ, exportArg(eventInit), popts) //nolint:wrapcheck
}), nil
},
"waitFor": func(opts sobek.Value) (*sobek.Promise, error) {
copts, err := parseFrameWaitForSelectorOptions(rt, opts, lo.Timeout())
if err != nil {
return nil, fmt.Errorf("parsing wait for options: %w", err)View on GitHub (pinned to 8d06114777)