grafana/k6 · error

Malformed attribute selector: ${selector}

Error message

Malformed attribute selector: ${selector}

What it means

Frame.IsEditable() (frame.go:1414) wraps the isEditable action failure as 'checking is %q editable'. The action resolves the selector to an attached element within Timeout and asks the page (via the injected utility) for the element's 'editable' state using a zero timeout, so the state check itself does not wait. Errors wrapped here are selector timeouts, strict-mode violations, frame/context destruction, or injected-script failures.

Source

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

      if (node.nodeType === 1 /*Node.ELEMENT_NODE*/) {
        result.push(node);
      }
    }
    return result;
  }
}

class AttributeEngine {
  constructor() {
    this._evaluator = new SelectorEvaluatorImpl();
  }
  queryAll(root, selector) {
    try {
      this._evaluator.begin();

      const parsed = parseAttributeSelector(selector, true);
      if (parsed.name || parsed.attributes.length !== 1)
        throw new Error("Malformed attribute selector: " + selector);
      const { name, value, caseSensitive } = parsed.attributes[0];
      const lowerCaseValue = caseSensitive ? null : value.toLowerCase();
      let matcher;
      if (value instanceof RegExp)
        matcher = (s) => !!s.match(value);
      else if (caseSensitive)
        matcher = (s) => s === value;
      else
        matcher = (s) => s.toLowerCase().includes(lowerCaseValue);
      const elements = this._evaluator._queryCSS({ scope: root, pierceShadow: true }, `[${name}]`);
      return elements.filter((e) => matcher(e.getAttribute(name)));
    } finally {
      this._evaluator.end();
    }
  };
}

class LabelEngine {

View on GitHub (pinned to 01ffac6f24)

Solutions

  1. Wait for the element first: await page.waitForSelector(sel, { state: 'attached', timeout: 10000 }).
  2. Use unique selectors (data-testid) to avoid strict-mode violations.
  3. Run the check on the frame that contains the element.
  4. Increase the per-call timeout on slow pages: page.isEditable(sel, { timeout: 60000 }).

Example fix

// before
const ok = await page.isEditable('#comment');

// after
await page.waitForSelector('#comment', { state: 'attached', timeout: 10000 });
const ok = await page.isEditable('#comment');
Defensive patterns

Strategy: try-catch

Validate before calling

await page.waitForSelector('#comment', { state: 'attached', timeout: 5000 });

Try / catch

try {
  return await page.isEditable(sel, { timeout: 10000 });
} catch (e) {
  if (String(e).includes('timed out')) throw new Error(`field never appeared: ${sel}`);
  throw e;
}

Prevention

When it happens

Trigger: No element matches before opts.Timeout; multiple matches with Strict:true; frame navigates or detaches during the check; the injected isEditable evaluation errors on exotic shadow-DOM/custom elements.

Common situations: Asserting form fields are editable before typing in e2e smoke checks; checking fields that render after async hydration; iframes re-rendering mid-check; strict mode newly enabled after a k6 upgrade.

Understand the failure class

Related errors


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