grafana/k6 · error · InvalidSelectorError

Error while parsing selector

Error message

Error while parsing selector `${selector}` - cannot use ${operator} in attribute with regular expression

What it means

Frame.FrameElement() (frame.go:990) returns the ElementHandle for a frame (the <iframe> or <frame> element in its parent document) via page.getFrameElement. The wrapper 'getting frame element' fires when that lookup fails: typically because the frame is already detached, its CDP session is gone, or resolving the frame owner through the DevTools protocol errored.

Solutions

  1. Re-acquire the frame right before use: const f = page.frames().find(fr => fr.name() === 'myframe'); then call f.frameElement().
  2. Do the call before triggering any action that can navigate or remove the iframe.
  3. Check page.frames() length/content to confirm the frame still exists.
  4. If the error appears after closing pages, restructure the script to finish iframe work before context/page close.

Example fix

// before
const f = page.frames()[2]; // captured earlier, iframe may be gone
const el = await f.frameElement();

// after
const f = page.frames().find(fr => fr.url().includes('/widget'));
if (!f) throw new Error('widget frame not attached');
const el = await f.frameElement();
Defensive patterns

Strategy: validation

Validate before calling

const f = page.frames().find(fr => fr.url().includes('/widget'));
if (!f) throw new Error('widget frame is not attached; cannot get frame element');
const el = await f.frameElement();

Try / catch

try {
  return await frame.frameElement();
} catch (e) {
  if (String(e).includes('getting frame element')) return null; // frame gone; caller re-discovers
  throw e;
}

Prevention

When it happens

Trigger: The iframe was removed from the DOM or navigated away before the call; the frame's page was closed; the parent document changed so the frame's owner node no longer resolves; CDP session issues after browser/context crash.

Common situations: Scripts holding a stale Frame reference from page.frames() after the SPA replaced an iframe; ad or embed iframes that unload quickly; calling FrameElement during teardown after context.close().

Related errors


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

Appendix: source

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

    const jsonPath = [];
    jsonPath.push(readAttributeToken());
    skipSpaces();
    while (next() === ".") {
      eat1();
      jsonPath.push(readAttributeToken());
      skipSpaces();
    }
    if (next() === "]") {
      eat1();
      return { name: jsonPath.join("."), jsonPath, op: "<truthy>", value: null, caseSensitive: false };
    }
    const operator = readOperator();
    let value = void 0;
    let caseSensitive = true;
    skipSpaces();
    if (next() === "/") {
      if (operator !== "=")
        throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - cannot use ${operator} in attribute with regular expression`);
      value = readRegularExpression();
    } else if (next() === `'` || next() === `"`) {
      value = readQuotedString(next()).slice(1, -1);
      skipSpaces();
      if (next() === "i" || next() === "I") {
        caseSensitive = false;
        eat1();
      } else if (next() === "s" || next() === "S") {
        caseSensitive = true;
        eat1();
      }
    } else {
      value = "";
      while (!EOL && (isCSSNameChar(next()) || next() === "+" || next() === "."))
        value += eat1();
      if (value === "true") {
        value = true;
      } else if (value === "false") {

View on GitHub (pinned to 3fcf5388d7)