grafana/k6 · error

"${attr.name}" must be one of ${values.map((v) => JSON.strin

Error message

"${attr.name}" must be one of ${values.map((v) => JSON.stringify(v)).join(", ")}

What it means

Frame.Hover() (frame.go:1265) wraps the internal pointer action failure with 'hovering %q'. Hover is a pointer action: it waits for the element to be attached and visible, computes its point, performs hit-target checking, and moves the mouse. The wrapped error can be a selector timeout, strict-mode violation, 'element is not visible', hit-target mismatch (another element intercepts the point), or frame detachment during the action.

Source

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

    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;
        break;
      }
      case "pressed": {
        validateSupportedRole(attr.name, kAriaPressedRoles, role);

View on GitHub (pinned to 01ffac6f24)

Solutions

  1. Ensure the element is visible and stable first: await page.locator(sel).waitFor({ state: 'visible' }).
  2. Dismiss blocking overlays (cookie banners, modals) before hovering.
  3. Set an explicit viewport large enough via browser launch options so the element is not clipped.
  4. If the target is animated, wait for a sentinel element that appears when the animation ends.
  5. Increase timeout per call: page.hover(sel, { timeout: 60000 }).

Example fix

// before
await page.hover('.menu-item');

// after
const item = page.locator('.menu-item');
await item.waitFor({ state: 'visible', timeout: 10000 });
await item.hover();
Defensive patterns

Strategy: try-catch

Validate before calling

const item = page.locator('.menu-item');
await item.waitFor({ state: 'visible', timeout: 5000 }); // hover needs a visible element

Try / catch

try {
  await page.hover(sel, { timeout: 10000 });
} catch (e) {
  const msg = String(e);
  if (msg.includes('not visible') || msg.includes('timed out')) {
    throw new Error(`hover target missing/hidden: ${sel}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Element not found before opts.Timeout; element exists but is hidden (display:none, zero size, outside scroll container); another overlay (cookie banner, tooltip, sticky header) intercepts the pointer at the element's point; navigation detaches the frame mid-hover.

Common situations: Hovering menu items of dropdowns that only render after a prior hover step; fixed-position overlays blocking the target on small viewports; animations leaving elements at 0x0; stale selectors after UI redesign.

Related errors


AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18). Data as JSON: /api/errors/312217c4ddc30fbc. Report an issue: GitHub.