{"record":{"id":"faa7ee2b11c7cda2","repo":"grafana/k6","slug":"parsing-element-tap-options-w","errorCode":null,"errorMessage":"parsing element tap options: %w","messagePattern":"parsing element tap options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/element_handle_mapping.go","lineNumber":246,"sourceCode":"\t\t\t}), nil\n\t\t},\n\t\t\"setInputFiles\": func(files sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleSetInputFilesOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles options: %w\", err)\n\t\t\t}\n\t\t\tvar pfiles common.Files\n\t\t\tif err := pfiles.Parse(vu.Context(), files); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles parameter: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.SetInputFiles(&pfiles, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"tap\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleTapOptions(eh.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element tap options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Tap(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"textContent\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := eh.TextContent()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t})\n\t\t},\n\t\t\"type\": func(text string, opts sobek.Value) (*sobek.Promise, error) {","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/browser/element_handle_mapping.go#L228-L264","documentation":"Thrown synchronously by ElementHandle.tap() when its options fail to parse. ElementHandleTapOptions embeds the base-pointer options plus modifiers; in common/element_handle_options.go only the 'position' export to map[string]float64 and the 'modifiers' export to []string can return an error. The mapping's (nil, error) return makes this a synchronous JS exception at call time.","triggerScenarios":"el.tap({ position: 'topRight' }) or { position: { x: '8' } } (non-numeric coordinates), el.tap({ modifiers: 'Shift' }) or { modifiers: [1] } (modifiers not a string array). force/trial/timeout never fail parsing.","commonSituations":"Mobile-emulation scripts where coordinates come from device metrics as strings; reusing click/hover option literals with tap; modifiers supplied as a single string from environment variables.","solutions":["Pass { position: { x: 8, y: 8 }, modifiers: ['Alt', 'Shift', 'Control', 'Meta'] } with correct types","Coerce and validate coordinates/modifiers in setup before the browser session starts","Reuse one shared type guard for all pointer actions (click, dblclick, hover, tap, check)","Wrap calls in try/catch; the error is not a promise rejection"],"exampleFix":"// before\nawait el.tap({ position: '10,20', modifiers: 'Shift' });\n\n// after\nawait el.tap({ position: { x: 10, y: 20 }, modifiers: ['Shift'] });","handlingStrategy":"type-guard","validationCode":"if (opts) {\n  if (opts.position !== undefined &&\n      (typeof opts.position !== 'object' || Array.isArray(opts.position) ||\n       !Number.isFinite(Number(opts.position.x)) || !Number.isFinite(Number(opts.position.y)))) {\n    throw new Error('tap(): position must be { x: number, y: number }');\n  }\n  if (opts.modifiers !== undefined &&\n      !(Array.isArray(opts.modifiers) && opts.modifiers.every(m => typeof m === 'string'))) {\n    throw new Error('tap(): modifiers must be an array of strings');\n  }\n}","typeGuard":"function isTapOpts(o) {\n  if (o == null) return true;\n  const posOk = o.position === undefined ||\n    (typeof o.position === 'object' && !Array.isArray(o.position) &&\n     Number.isFinite(Number(o.position.x)) && Number.isFinite(Number(o.position.y)));\n  const modOk = o.modifiers === undefined ||\n    (Array.isArray(o.modifiers) && o.modifiers.every(m => typeof m === 'string'));\n  return posOk && modOk;\n}","tryCatchPattern":"try {\n  await el.tap(opts);\n} catch (e) {\n  if (/parsing element tap options/.test(String(e.message))) {\n    console.log(`fix tap options: ${e.message}`);\n  } else throw e;\n}","preventionTips":["Mobile-emulation coordinate sources (device metrics, env vars) often yield strings: coerce with Number() first","Reuse the same pointer-options guard as click/hover/dblclick","Remember the throw is synchronous; .catch() on the returned promise never sees it"],"tags":["k6","browser","element-handle","tap","option-parsing"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}