{"record":{"id":"d08ee3155c22b8a7","repo":"grafana/k6","slug":"provided-selector-is-empty","errorCode":null,"errorMessage":"provided selector is empty","messagePattern":"provided selector is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/selectors.go","lineNumber":51,"sourceCode":"\ntype SelectorPart struct {\n\tName string `json:\"name\"`\n\tBody string `json:\"body\"`\n}\n\ntype Selector struct {\n\tSelector string          `json:\"selector\"`\n\tParts    []*SelectorPart `json:\"parts\"`\n\n\t// By default chained queries resolve to elements matched by the last selector,\n\t// but a selector can be prefixed with `*` to capture elements resolved by\n\t// an intermediate selector.\n\tCapture *int `json:\"capture\"`\n}\n\nfunc NewSelector(selector string) (*Selector, error) {\n\tif selector == \"\" {\n\t\treturn nil, errors.New(\"provided selector is empty\")\n\t}\n\n\ts := Selector{\n\t\tSelector: selector,\n\t\tParts:    make([]*SelectorPart, 0, 1),\n\t\tCapture:  nil,\n\t}\n\terr := s.parse()\n\treturn &s, err\n}\n\nfunc (s *Selector) appendPart(p *SelectorPart, capture bool) error {\n\ts.Parts = append(s.Parts, p)\n\tif capture {\n\t\tif s.Capture != nil {\n\t\t\treturn errors.New(\"only one of the selectors can capture using * modifier\")\n\t\t}\n\t\ts.Capture = new(int)","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/selectors.go#L33-L69","documentation":"NewSelector (selectors.go:45-56) parses every selector used by page.$, page.$$, page.waitForSelector and locators. An empty string has no parts to parse, so it fails fast with 'provided selector is empty' instead of querying the DOM with a meaningless selector.","triggerScenarios":"page.$(''), page.waitForSelector(''), page.locator(''); a selector built from an undefined/null/empty variable; template literals where a parameter is missing; empty entries in data-driven selector arrays.","commonSituations":"Parameterized selectors from CSV/JSON data containing empty cells; env-driven selectors where the variable was never set; destructuring mistakes producing undefined stringified to ''.","solutions":["Validate the selector is a non-empty string before passing it to browser APIs","Filter empty entries out of data-driven selector arrays before iterating","Fail fast with a clear message when a selector-producing config value is missing"],"exampleFix":"// before\nconst sel = selectors[i]; // possibly ''\nawait page.waitForSelector(sel);\n\n// after\nconst sel = selectors[i];\nif (!sel) throw new Error(`selector at index ${i} is empty`);\nawait page.waitForSelector(sel);","handlingStrategy":"validation","validationCode":"if (typeof selector !== 'string' || selector.trim() === '') {\n  throw new Error(`invalid selector: ${JSON.stringify(selector)}`);\n}\nawait page.waitForSelector(selector);","typeGuard":"const isNonEmptySelector = (s) => typeof s === 'string' && s.trim().length > 0;","tryCatchPattern":null,"preventionTips":["Validate selector strings at the data source (filter empty CSV/JSON entries)","Fail fast on missing env-driven selector config with a clear message","Centralize selector access behind helpers that assert non-emptiness"],"tags":["browser","selector","validation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}