grafana/k6 · error
Role must not be empty
Error message
Role must not be empty
What it means
After the inputValue evaluation succeeds (frame.go:1385), k6 asserts the CDP-returned value is a string; a non-string yields 'unexpected type %T'. The injected JS returns element.value, which for input/textarea/select is always a string per spec, so this defensive check fires only on abnormal pages: a patched value getter on the prototype, or a protocol conversion quirk. It indicates page tampering or a k6/browser bug rather than a wrong API call.
Source
Thrown at internal/js/modules/k6/browser/common/js/injected_script.js:1284
shadows.push(root.shadowRoot);
for (const element of root.querySelectorAll("*")) {
match(element);
if (element.shadowRoot)
shadows.push(element.shadowRoot);
}
shadows.forEach(query);
};
query(scope);
return result;
}
function createRoleEngine(internal) {
return {
queryAll: (scope, selector) => {
const parsed = parseAttributeSelector(selector, true);
const role = parsed.name.toLowerCase();
if (!role)
throw new Error(`Role must not be empty`);
const options = validateAttributes(parsed.attributes, role);
beginAriaCaches();
try {
return queryRole(scope, options, internal);
} finally {
endAriaCaches();
}
}
};
}
// packages/injected/src/selectorEvaluator.ts
var SelectorEvaluatorImpl = class {
constructor() {
this._retainCacheCounter = 0;
this._cacheText = new k6BrowserNative.Map();
this._cacheQueryCSS = new k6BrowserNative.Map();
}View on GitHub (pinned to 01ffac6f24)
Solutions
- Inspect directly: const v = await page.evaluate(`document.querySelector(sel).value`); check typeof v.
- Read the value via page.evaluate when the getter is patched.
- Report a grafana/k6 issue with a minimal repro if the raw property is a string but the error persists.
- Use a pinned, standard Chromium build.
Example fix
// before
const v = await page.inputValue('#email'); // unexpected type ...
// after
const v = await page.evaluate(`document.querySelector('#email').value`);
if (typeof v !== 'string') throw new Error('value getter patched'); Defensive patterns
Strategy: fallback
Validate before calling
const t = await page.evaluate(`
(() => { const el = document.querySelector('#email'); return el ? typeof el.value : 'no-el'; })()
`);
if (t !== 'string') throw new Error('value getter patched'); Type guard
function isValueString(v) { return typeof v === 'string'; } Try / catch
try {
return await page.inputValue(sel);
} catch (e) {
if (String(e).includes('unexpected type')) {
return await page.evaluate(`document.querySelector('${sel}').value`);
}
throw e;
} Prevention
- On protected forms, read values via evaluate.
- Avoid custom Chromium builds that deviate from protocol behavior.
- Report reproducible type mismatches to grafana/k6.
When it happens
Trigger: Page defines a getter for HTMLInputElement.prototype.value returning non-strings; anti-bot frameworks or frameworks like older React versions interfering with native accessors; CDP value conversion edge cases; Chromium version mismatch.
Common situations: Testing protected login/checkout flows where bot detection patches input values; custom form libraries overriding value; k6 browser module paired with a non-standard Chromium.
Related errors
- Error while parsing selector `${selector}` - selector cannot
- "level" attribute must be compared to a number
- "name" attribute must be a string or a regular expression
- Unexpected end of selector while parsing selector `${selecto
- Error while parsing selector `${selector}` - cannot use ${op
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/4bd0551638e50144.
Report an issue: GitHub.