{"record":{"id":"1fbe7d1e250ade92","repo":"grafana/k6","slug":"attr-attribute-is-only-supported-for-roles","errorCode":null,"errorMessage":"\"${attr}\" attribute is only supported for roles: ${roles.slice().sort().map((role2) => `\"${role2}\"`).join(\", \")}","messagePattern":"\"(.+?)\" attribute is only supported for roles: (.+?)\"`\\)\\.join\\(\", \"\\)\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/js/injected_script.js","lineNumber":1150,"sourceCode":"  result.name = readIdentifier();\n  skipSpaces();\n  while (next() === \"[\") {\n    result.attributes.push(readAttribute());\n    skipSpaces();\n  }\n  if (!EOL)\n    syntaxError(void 0);\n  if (!result.name && !result.attributes.length)\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - selector cannot be empty`);\n  return result;\n}\n\n// packages/injected/src/roleSelectorEngine.ts\nvar kSupportedAttributes = [\"selected\", \"checked\", \"pressed\", \"expanded\", \"level\", \"disabled\", \"name\", \"include-hidden\"];\nkSupportedAttributes.sort();\nfunction validateSupportedRole(attr, roles, role) {\n  if (!roles.includes(role))\n    throw new Error(`\"${attr}\" attribute is only supported for roles: ${roles.slice().sort().map((role2) => `\"${role2}\"`).join(\", \")}`);\n}\nfunction validateSupportedValues(attr, values) {\n  if (attr.op !== \"<truthy>\" && !values.includes(attr.value))\n    throw new Error(`\"${attr.name}\" must be one of ${values.map((v) => JSON.stringify(v)).join(\", \")}`);\n}\nfunction validateSupportedOp(attr, ops) {\n  if (!ops.includes(attr.op))\n    throw new Error(`\"${attr.name}\" does not support \"${attr.op}\" matcher`);\n}\nfunction validateAttributes(attrs, role) {\n  const options = { role };\n  for (const attr of attrs) {\n    switch (attr.name) {\n      case \"checked\": {\n        validateSupportedRole(attr.name, kAriaCheckedRoles, role);\n        validateSupportedValues(attr, [true, false, \"mixed\"]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.checked = attr.op === \"<truthy>\" ? true : attr.value;","sourceCodeStart":1132,"sourceCodeEnd":1168,"githubUrl":"https://github.com/grafana/k6/blob/3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee/internal/js/modules/k6/browser/common/js/injected_script.js#L1132-L1168","documentation":"Frame.Goto() (frame.go:1247) wraps every FrameManager.NavigateFrame failure as 'navigating frame to %q'. NavigateFrame calls CDP Page.navigate and then waits for the frame's navigation event and the requested lifecycle state (WaitUntil, default 'load') within Timeout (default ~30s). Failures include CDP navigation errors (net::ERR_NAME_NOT_RESOLVED, net::ERR_CONNECTION_REFUSED, invalid URL), timeouts waiting for lifecycle events, and cancellation when the browser/page closes.","triggerScenarios":"CDP Page.navigate rejects the URL (net::ERR_NAME_NOT_RESOLVED, net::ERR_CONNECTION_REFUSED, net::ERR_INVALID_ADDRESS, net::ERR_ABORTED); the frame never emits the requested lifecycle event (WaitUntil 'load') within Timeout; the page or browser context is closed while navigation is pending; the navigation event is swallowed because the frame navigated again before matching newDocumentID.","commonSituations":"Load tests hitting DNS resolution failures or connection-refused in the test environment; navigating before a previous navigation finished; pages whose 'load' event never fires (long-polling, heavy third-party assets) so the lifecycle wait times out; using a hostname only resolvable inside a network k6 cannot reach; page closed mid-navigation by another concurrent iteration.","solutions":["Verify the URL opens in a browser/HEAD request from the same host k6 runs on (DNS, firewall, TLS).","Choose a lifecycle event that matches the page: page.goto(url, { waitUntil: 'domcontentloaded' }) instead of the default 'load'.","Raise the navigation timeout: page.goto(url, { timeout: 60000 }).","URL-encode or correct malformed URLs (missing scheme, spaces, bad query strings).","If pages legitimately never settle, navigate with waitUntil 'commit'-equivalent behavior by waiting for a selector instead of lifecycle."],"exampleFix":"// before\nawait page.goto('https://app.example.com/dashboard');\n\n// after\nawait page.goto('https://app.example.com/dashboard', {\n  waitUntil: 'domcontentloaded',\n  timeout: 60000,\n});","handlingStrategy":"try-catch","validationCode":"const url = 'https://app.example.com/dashboard';\nconst u = new URL(url); // throws on malformed URL before touching the browser\nif (!['http:', 'https:'].includes(u.protocol)) throw new Error('unsupported scheme');","typeGuard":null,"tryCatchPattern":"try {\n  await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });\n} catch (e) {\n  const msg = String(e);\n  if (msg.includes('ERR_NAME_NOT_RESOLVED') || msg.includes('ERR_CONNECTION_REFUSED'))\n    throw new Error(`target unreachable from load generator: ${url}`);\n  if (msg.includes('timed out')) throw new Error(`page never reached load state: ${url}`);\n  throw e;\n}","preventionTips":["Validate URLs (scheme, encoding) with new URL() before goto.","Use waitUntil 'domcontentloaded' for pages with third-party assets that delay 'load'.","Set a realistic timeout and verify DNS/firewall reachability from the k6 host."],"tags":["k6","browser","frame","goto","navigation","timeout","network"],"backgroundTag":"page-navigation-failed","analyzedSha":"3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}