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
- 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.
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
- 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.
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
- parsing frame navigation options to
- an error occurred communicating with k6 Cloud
- " " does not support " " matcher
- " " must be one of
- Error while parsing selector
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)