grafana/k6 · error

checking state of element

Error message

checking state %q of element %q

What it means

Returned by the per-state element check (used by waitFor state=visible/hidden/enabled/... style waits): the injected script evaluated successfully but its return value was neither a string ('done'/'error:...' protocol) nor a bool. This is an internal invariant violation of the Go/JS contract inside the k6 browser module, not a normal page condition.

Solutions

  1. Upgrade (or pin) k6 to a version where the injected-script contract matches the Go side
  2. Test the same script against a plain page (example.com) to confirm it is page-specific interference
  3. If reproducible on a minimal page, file a k6 issue with the script, selector, and state that triggered it
  4. As a workaround, replace state waits with an explicit condition via el.getAttribute/isVisible polling
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await el.waitFor({ state: 'visible' });
} catch (e) {
  if (/checking state/.test(String(e))) {
    // internal eval contract issue: report it, then fall back to polling
    for (let i = 0; i < 50 && !(await el.isVisible()); i++) {
      await page.waitForTimeout(200);
    }
  } else throw e;
}

Prevention

When it happens

Trigger: h.evalWithScript with the state-checking JS returns an unexpected type (number, object, undefined) because the injected script was corrupted, a page overrode primitives used by the evaluation, or an internal regression changed the protocol; any waitFor* on element state can surface it.

Common situations: Pages that monkey-patch Function.prototype/JSON or define hostile prototypes breaking the injected script; version mismatches after upgrading k6 where the injected JS bundle changed; extremely rare in stock usage.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/067b05630519f0ff. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/element_handle.go:205

			return injected.checkElementState(node, state);
		}
	`
	opts := evalOptions{
		forceCallable: true,
		returnByValue: true,
	}
	result, err := h.evalWithScript(h.ctx, opts, fn, state)
	if err != nil {
		return nil, err
	}
	switch v := result.(type) {
	case string: // An error happened (returned as "error:..." from JS)
		return nil, errorFromDOMError(v)
	case bool:
		return &v, nil
	}

	return nil, fmt.Errorf(
		"checking state %q of element %q", state, reflect.TypeOf(result))
}

func (h *ElementHandle) click(p *Position, opts *MouseClickOptions) error {
	return h.frame.page.Mouse.click(p.X, p.Y, opts)
}

// This will get the clickable point of the element relative to the page even
// when the element is in an iframe. In some cases this isn't the case and we
// need to translate the point to the page.
func (h *ElementHandle) clickablePoint() (*Position, error) {
	r, err := h.BoundingBox()
	if err != nil {
		return nil, fmt.Errorf("finding clickable point: %w", err)
	}
	return &Position{X: r.X + r.Width/2, Y: r.Y + r.Height/2}, nil
}

View on GitHub (pinned to 3fcf5388d7)