{"record":{"id":"8fe3c3cd09afec7a","repo":"grafana/k6","slug":"level-attribute-must-be-compared-to-a-number","errorCode":null,"errorMessage":"\"level\" attribute must be compared to a number","messagePattern":"\"level\" attribute must be compared to a number","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/js/injected_script.js","lineNumber":1197,"sourceCode":"        validateSupportedRole(attr.name, kAriaSelectedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.selected = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"expanded\": {\n        validateSupportedRole(attr.name, kAriaExpandedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.expanded = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"level\": {\n        validateSupportedRole(attr.name, kAriaLevelRoles, role);\n        if (typeof attr.value === \"string\")\n          attr.value = +attr.value;\n        if (attr.op !== \"=\" || typeof attr.value !== \"number\" || Number.isNaN(attr.value))\n          throw new Error(`\"level\" attribute must be compared to a number`);\n        options.level = attr.value;\n        break;\n      }\n      case \"disabled\": {\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.disabled = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"name\": {\n        if (attr.op === \"<truthy>\")\n          throw new Error(`\"name\" attribute must have a value`);\n        if (typeof attr.value !== \"string\" && !(attr.value instanceof RegExp))\n          throw new Error(`\"name\" attribute must be a string or a regular expression`);\n        options.name = attr.value;\n        options.nameOp = attr.op;\n        options.exact = attr.caseSensitive;\n        break;","sourceCodeStart":1179,"sourceCodeEnd":1215,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/js/modules/k6/browser/common/js/injected_script.js#L1179-L1215","documentation":"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.","triggerScenarios":"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.","commonSituations":"Testing sites with bot-detection scripts that poison DOM getters; pages with aggressive custom-elements polyfills; unusual Chromium builds via executablePath.","solutions":["Inspect what the page really returns: const v = await page.evaluate(`document.querySelector(sel).innerHTML`); console.log(typeof v).","Read the markup via page.evaluate instead of the innerHTML API when prototypes are patched.","Report to grafana/k6 with a minimal repro page if DevTools shows a string but the error persists.","Launch a standard, pinned Chromium to rule out browser-specific behavior."],"exampleFix":"// before\nconst html = await page.innerHTML('#app'); // unexpected type ...\n\n// after\nconst html = await page.evaluate(`document.querySelector('#app').innerHTML`);\nif (typeof html !== 'string') throw new Error('innerHTML getter is patched');","handlingStrategy":"fallback","validationCode":"const t = await page.evaluate(`\n  (() => { const el = document.querySelector('#app'); return el ? typeof el.innerHTML : 'no-el'; })()\n`);\nif (t !== 'string') throw new Error('innerHTML getter patched');","typeGuard":"function isHtmlString(v) { return typeof v === 'string'; }","tryCatchPattern":"try {\n  return await page.innerHTML(sel);\n} catch (e) {\n  if (String(e).includes('unexpected type')) {\n    return await page.evaluate(`document.querySelector('${sel}').innerHTML`);\n  }\n  throw e;\n}","preventionTips":["On tampering-prone sites, read markup via evaluate directly.","Pin the Chromium version used by k6.","Escalate persistent unexpected-type results to grafana/k6."],"tags":["k6","browser","innerhtml","type-assertion","cdp"],"backgroundTag":"unexpected-eval-return-type","analyzedSha":"01ffac6f245854c1b8adc6a69857c76a15f90022","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}