grafana/k6 · error

" " attribute is only supported for roles: "`).join(", ")}

Error message

"${attr}" attribute is only supported for roles: ${roles.slice().sort().map((role2) => `"${role2}"`).join(", ")}

What it means

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.

Solutions

  1. Verify the URL opens in a browser/HEAD request from the same host k6 runs on (DNS, firewall, TLS).
  2. Choose a lifecycle event that matches the page: page.goto(url, { waitUntil: 'domcontentloaded' }) instead of the default 'load'.
  3. Raise the navigation timeout: page.goto(url, { timeout: 60000 }).
  4. URL-encode or correct malformed URLs (missing scheme, spaces, bad query strings).
  5. If pages legitimately never settle, navigate with waitUntil 'commit'-equivalent behavior by waiting for a selector instead of lifecycle.

Example fix

// before
await page.goto('https://app.example.com/dashboard');

// after
await page.goto('https://app.example.com/dashboard', {
  waitUntil: 'domcontentloaded',
  timeout: 60000,
});
Defensive patterns

Strategy: try-catch

Validate before calling

const url = 'https://app.example.com/dashboard';
const u = new URL(url); // throws on malformed URL before touching the browser
if (!['http:', 'https:'].includes(u.protocol)) throw new Error('unsupported scheme');

Try / catch

try {
  await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
} catch (e) {
  const msg = String(e);
  if (msg.includes('ERR_NAME_NOT_RESOLVED') || msg.includes('ERR_CONNECTION_REFUSED'))
    throw new Error(`target unreachable from load generator: ${url}`);
  if (msg.includes('timed out')) throw new Error(`page never reached load state: ${url}`);
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/1fbe7d1e250ade92. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/js/injected_script.js:1150

  result.name = readIdentifier();
  skipSpaces();
  while (next() === "[") {
    result.attributes.push(readAttribute());
    skipSpaces();
  }
  if (!EOL)
    syntaxError(void 0);
  if (!result.name && !result.attributes.length)
    throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - selector cannot be empty`);
  return result;
}

// packages/injected/src/roleSelectorEngine.ts
var kSupportedAttributes = ["selected", "checked", "pressed", "expanded", "level", "disabled", "name", "include-hidden"];
kSupportedAttributes.sort();
function validateSupportedRole(attr, roles, role) {
  if (!roles.includes(role))
    throw new Error(`"${attr}" attribute is only supported for roles: ${roles.slice().sort().map((role2) => `"${role2}"`).join(", ")}`);
}
function validateSupportedValues(attr, values) {
  if (attr.op !== "<truthy>" && !values.includes(attr.value))
    throw new Error(`"${attr.name}" must be one of ${values.map((v) => JSON.stringify(v)).join(", ")}`);
}
function validateSupportedOp(attr, ops) {
  if (!ops.includes(attr.op))
    throw new Error(`"${attr.name}" does not support "${attr.op}" matcher`);
}
function validateAttributes(attrs, role) {
  const options = { role };
  for (const attr of attrs) {
    switch (attr.name) {
      case "checked": {
        validateSupportedRole(attr.name, kAriaCheckedRoles, role);
        validateSupportedValues(attr, [true, false, "mixed"]);
        validateSupportedOp(attr, ["<truthy>", "="]);
        options.checked = attr.op === "<truthy>" ? true : attr.value;

View on GitHub (pinned to 3fcf5388d7)