grafana/k6 · error

selecting option on %q: %w

Error message

selecting option on %q: %w

What it means

Frame.SelectOption() wraps the internal select-option action; any failure — element not found, not a <select> element, actionability timeout, or a mid-action detach — is reported as 'selecting option on "<selector>": <cause>'. The actionable detail is the wrapped cause, not the prefix.

Source

Thrown at internal/js/modules/k6/browser/common/frame.go:1706

	act := f.newAction(
		selector, DOMElementStateAttached, opts.Strict, press,
		[]string{}, false, withRetry, opts.NoWaitAfter, opts.Timeout,
	)
	if _, err := call(f.ctx, act, opts.Timeout); err != nil {
		return errorFromDOMError(err)
	}

	return nil
}

// SelectOption selects the given options and returns the array of
// option values of the first element found that matches the selector.
func (f *Frame) SelectOption(selector string, values []any, popts *FrameSelectOptionOptions) ([]string, error) {
	f.log.Debugf("Frame:SelectOption", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

	v, err := f.selectOption(selector, values, popts)
	if err != nil {
		return nil, fmt.Errorf("selecting option on %q: %w", selector, err)
	}

	applySlowMo(f.ctx)

	return v, nil
}

func (f *Frame) selectOption(selector string, values []any, opts *FrameSelectOptionOptions) ([]string, error) {
	selectOption := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
		return handle.selectOption(apiCtx, values)
	}
	act := f.newAction(
		selector, DOMElementStateAttached, opts.Strict, selectOption,
		[]string{}, opts.Force, withRetry, opts.NoWaitAfter, opts.Timeout,
	)
	v, err := call(f.ctx, act, opts.Timeout)
	if err != nil {
		return nil, errorFromDOMError(err)

View on GitHub (pinned to 93accf6570)

Solutions

  1. Confirm the target is a real <select> element (inspect with evaluate(() => document.querySelector(sel).tagName)); if it is a custom widget, click it and click options instead.
  2. Pass the right matcher shape: { value: 'x' }, { label: 'Text' }, or { index: 2 }.
  3. Wait for the select to be visible/enabled before the call.
  4. If the select is styled but native, use { force: true } to bypass visibility checks.

Example fix

// before
await frame.selectOption('.nice-select', 'opt1'); // div wrapper, not <select>

// after
await frame.selectOption('select#country', { value: 'opt1' });
// or for custom dropdowns:
await frame.click('.dropdown-toggle');
await frame.click('li[data-value="opt1"]');
Defensive patterns

Strategy: validation

Validate before calling

const tag = await frame.evaluate(s => document.querySelector(s)?.tagName, sel);
if (tag !== 'SELECT') throw new Error(`${sel} is ${tag}, not <select>`);

Type guard

const isNativeSelect = (t) => t === 'SELECT';

Try / catch

try { await frame.selectOption(sel, { value: v }); }
catch (e) { if (/selecting option on/.test(e.message)) { /* check tagName, matcher shape, visibility */ } throw e; }

Prevention

When it happens

Trigger: frame.selectOption(sel, values) where sel does not match a <select> element (e.g. a custom div dropdown), the select is hidden/disabled, values do not match any option, or strict mode finds multiple matches. Also when the element detaches between resolution and click.

Common situations: Modern UIs use div/role=listbox dropdowns where selectOption cannot work — a real <select> is required; selecting by value when the option only has a label; hidden native selects styled with display:none (materialize/bootstrap overrides).

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/4d23b76319673754. Report an issue: GitHub.