grafana/k6 · error
%q is not a valid DOM state
Error message
%q is not a valid DOM state
What it means
parseFrameWaitForSelectorOptions validates the `state` option of frame.waitForSelector/page.waitForSelector against the known DOM element states via DOMElementStateIDFromString. Only 'attached', 'detached', 'visible', and 'hidden' are accepted; any other string produces '%q is not a valid DOM state'.
Source
Thrown at internal/js/modules/k6/browser/browser/frame_mapping.go:938
// parseFrameWaitForSelectorOptions parses the frame waitForSelector options from a Sobek value.
func parseFrameWaitForSelectorOptions(
rt *sobek.Runtime, opts sobek.Value,
defaultTimeout time.Duration,
) (*common.FrameWaitForSelectorOptions, error) {
wsopts := common.NewFrameWaitForSelectorOptions(defaultTimeout)
if k6common.IsNullish(opts) {
return wsopts, nil
}
obj := opts.ToObject(rt)
for _, k := range obj.Keys() {
switch k {
case "state":
state := obj.Get(k).String()
if s, ok := common.DOMElementStateIDFromString(state); ok {
wsopts.State = s
} else {
return wsopts, fmt.Errorf("%q is not a valid DOM state", state)
}
case "strict":
wsopts.Strict = obj.Get(k).ToBoolean()
case "timeout":
wsopts.Timeout = time.Duration(obj.Get(k).ToInteger()) * time.Millisecond
}
}
return wsopts, nil
}
// parseFrameIsHiddenOptions parses the frame isHidden options from a Sobek value.
//
//nolint:unparam
func parseFrameIsHiddenOptions(
rt *sobek.Runtime, opts sobek.Value,
) (*common.FrameIsHiddenOptions, error) {
tcopts := common.NewFrameIsHiddenOptions()
tcopts.Strict = parseStrict(rt, opts)View on GitHub (pinned to 8d06114777)
Solutions
- Use one of the four valid states: 'attached', 'detached', 'visible', or 'hidden' (lowercase)
- If you need Playwright's 'stable', replace it with 'visible' plus an explicit visibility check
- Fix casing and typos — matching is exact string comparison
- Consult k6 docs for the exact supported state values in your k6 version
Example fix
// before
await page.waitForSelector('#btn', { state: 'stable' });
// after
await page.waitForSelector('#btn', { state: 'visible' }); Defensive patterns
Strategy: validation
Validate before calling
const DOM_STATES = ['attached', 'detached', 'visible', 'hidden'];
function validWaitForSelectorOptions(opts) {
return opts == null || opts.state === undefined || DOM_STATES.includes(opts.state);
} Type guard
function isValidDOMState(v) {
return ['attached', 'detached', 'visible', 'hidden'].includes(v);
} Try / catch
try {
await page.waitForSelector(sel, { state: 'visible' });
} catch (e) {
if (String(e).includes('is not a valid DOM state')) {
throw new Error('state must be attached|detached|visible|hidden: ' + e);
}
throw e;
} Prevention
- Remember only four states exist: attached, detached, visible, hidden
- Replace Playwright-only 'stable' with 'visible' plus an explicit wait
- Keep state values lowercase and free of typos
- Share a constants file for valid DOM states across your test suite
When it happens
Trigger: Calling page.waitForSelector(sel, { state: 'visibility' }) or any value outside the four valid states, e.g. 'visibile' (typo), 'shown', 'stable', 'enabled', or wrong casing such as 'Visible'.
Common situations: Porting from Playwright, which additionally accepts 'stable' for waitForSelector; typos like 'visibile'; forgetting that k6 browser only implements a subset of Playwright's state values; mixing up waitForSelector state with waitForFunction or element state APIs.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- parsing waitForSelector %q options: %w
- %q is an invalid permission
- waitFor retry threshold reached
- parsing wait for selector %q options: %w
- parsing goto options: %w
AI-assisted analysis of grafana/k6@8d06114777 (2026-09-14).
Data as JSON: /api/errors/decb181330264db3.
Report an issue: GitHub.