{"record":{"id":"ad9d5dd3d4faa79f","repo":"grafana/k6","slug":"parsing-selector-q-w","errorCode":null,"errorMessage":"parsing selector %q: %w","messagePattern":"parsing selector %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/element_handle.go","lineNumber":1192,"sourceCode":"\t}\n\tpressAction := h.newAction(\n\t\t[]string{}, press, false, withRetry, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, pressAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"pressing %q on element: %w\", key, err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// Query runs \"element.querySelector\" within the page. If no element matches the selector,\n// the return value resolves to \"null\".\nfunc (h *ElementHandle) Query(selector string, strict bool) (_ *ElementHandle, rerr error) {\n\tparsedSelector, err := NewSelector(selector)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing selector %q: %w\", selector, err)\n\t}\n\n\t// Check for frame navigation in the selector\n\tframeNavIndex := h.findFrameNavigationIndex(parsedSelector)\n\tif frameNavIndex != -1 {\n\t\t// Strict is true because we assume the user is interested in the element\n\t\t// in the frame and not the frame it is in.\n\t\topts := &FrameWaitForSelectorOptions{\n\t\t\tState:   DOMElementStateAttached,\n\t\t\tTimeout: h.frame.defaultTimeout(),\n\t\t\tStrict:  true,\n\t\t}\n\n\t\tframe, afterFrameSelector, err := h.stepIntoFrame(h.ctx, parsedSelector, frameNavIndex, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n","sourceCodeStart":1174,"sourceCodeEnd":1210,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/element_handle.go#L1174-L1210","documentation":"ElementHandle.Query() rejects the selector before touching the page: NewSelector (selectors.go:49) failed to parse it. Concrete parse failures: an empty selector string, more than one '*' capture prefix in a '>>' chain ('only one of the selectors can capture using * modifier'), or a part whose engine prefix is not a supported query engine.","triggerScenarios":"Calling $() with '' (often a dynamically built selector that evaluated to empty); using two captures like '*css=a >> *text=Login'; using an engine prefix k6 does not support (only css/xpath/text and the recognized engine names map); stray quotes in '>>' chains.","commonSituations":"Selectors interpolated from variables/CSV data that can be blank; Playwright selectors pasted in that rely on engines k6's parser doesn't recognize; copy-paste typos of the capture modifier.","solutions":["Log and assert the selector string is non-empty before use (especially dynamic ones)","Use at most one '*' capture prefix in a chained selector","Stick to supported engines: bare CSS, 'xpath=', 'text=', or recognized engine= prefixes","Test the exact selector string in browser devtools / a minimal k6 script first"],"exampleFix":"// before\nawait page.$(`*css=tr >> *text=Delete`); // two captures -> parse error\n// after\nawait page.$(`*css=tr >> text=Delete`); // single capture","handlingStrategy":"validation","validationCode":"// Validate a k6 selector string before use\nfunction checkSelector(s) {\n  if (typeof s !== 'string' || s.trim() === '') throw new Error('selector is empty');\n  const captures = (s.match(/(^|\\s|>>)\\*/g) || []).length;\n  if (captures > 1) throw new Error('only one * capture allowed');\n  return s;\n}","typeGuard":null,"tryCatchPattern":"try { await el.$(sel); }\ncatch (e) { if (/parsing selector/.test(e.message)) { /* fix sel, it never reached the page */ } throw e; }","preventionTips":["Never feed unvalidated dynamic strings into selectors","Remember parse errors are client-side: no page interaction happened","One '*' capture maximum per '>>' chain"],"tags":["selector","validation","browser"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}