grafana/k6 · error

"level" attribute must be compared to a number

Error message

"level" attribute must be compared to a number

What it means

After evaluating element.innerHTML successfully (frame.go:1317), k6 asserts the CDP-returned value is a Go string; otherwise it returns 'unexpected type %T'. The DOM property is spec-defined as a string, so a non-string result means abnormal page behavior: JavaScript overriding the innerHTML getter on Element/HTMLElement prototypes, or a DevTools protocol value-conversion quirk. It is a defensive check and usually signals page tampering or a k6/browser-module bug rather than a script mistake.

Source

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

        validateSupportedRole(attr.name, kAriaSelectedRoles, role);
        validateSupportedValues(attr, [true, false]);
        validateSupportedOp(attr, ["<truthy>", "="]);
        options.selected = attr.op === "<truthy>" ? true : attr.value;
        break;
      }
      case "expanded": {
        validateSupportedRole(attr.name, kAriaExpandedRoles, role);
        validateSupportedValues(attr, [true, false]);
        validateSupportedOp(attr, ["<truthy>", "="]);
        options.expanded = attr.op === "<truthy>" ? true : attr.value;
        break;
      }
      case "level": {
        validateSupportedRole(attr.name, kAriaLevelRoles, role);
        if (typeof attr.value === "string")
          attr.value = +attr.value;
        if (attr.op !== "=" || typeof attr.value !== "number" || Number.isNaN(attr.value))
          throw new Error(`"level" attribute must be compared to a number`);
        options.level = attr.value;
        break;
      }
      case "disabled": {
        validateSupportedValues(attr, [true, false]);
        validateSupportedOp(attr, ["<truthy>", "="]);
        options.disabled = attr.op === "<truthy>" ? true : attr.value;
        break;
      }
      case "name": {
        if (attr.op === "<truthy>")
          throw new Error(`"name" attribute must have a value`);
        if (typeof attr.value !== "string" && !(attr.value instanceof RegExp))
          throw new Error(`"name" attribute must be a string or a regular expression`);
        options.name = attr.value;
        options.nameOp = attr.op;
        options.exact = attr.caseSensitive;
        break;

View on GitHub (pinned to 01ffac6f24)

Solutions

  1. Inspect what the page really returns: const v = await page.evaluate(`document.querySelector(sel).innerHTML`); console.log(typeof v).
  2. Read the markup via page.evaluate instead of the innerHTML API when prototypes are patched.
  3. Report to grafana/k6 with a minimal repro page if DevTools shows a string but the error persists.
  4. Launch a standard, pinned Chromium to rule out browser-specific behavior.

Example fix

// before
const html = await page.innerHTML('#app'); // unexpected type ...

// after
const html = await page.evaluate(`document.querySelector('#app').innerHTML`);
if (typeof html !== 'string') throw new Error('innerHTML getter is patched');
Defensive patterns

Strategy: fallback

Validate before calling

const t = await page.evaluate(`
  (() => { const el = document.querySelector('#app'); return el ? typeof el.innerHTML : 'no-el'; })()
`);
if (t !== 'string') throw new Error('innerHTML getter patched');

Type guard

function isHtmlString(v) { return typeof v === 'string'; }

Try / catch

try {
  return await page.innerHTML(sel);
} catch (e) {
  if (String(e).includes('unexpected type')) {
    return await page.evaluate(`document.querySelector('${sel}').innerHTML`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Page defines Object.defineProperty(HTMLElement.prototype, 'innerHTML', ...) returning non-strings; anti-bot or framework code patching DOM accessors; CDP returning an unserializable RemoteObject; Chromium version mismatch with the k6 browser module.

Common situations: Testing sites with bot-detection scripts that poison DOM getters; pages with aggressive custom-elements polyfills; unusual Chromium builds via executablePath.

Related errors


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