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

  1. Use one of the four valid states: 'attached', 'detached', 'visible', or 'hidden' (lowercase)
  2. If you need Playwright's 'stable', replace it with 'visible' plus an explicit visibility check
  3. Fix casing and typos — matching is exact string comparison
  4. 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

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


AI-assisted analysis of grafana/k6@8d06114777 (2026-09-14). Data as JSON: /api/errors/decb181330264db3. Report an issue: GitHub.