JuliusBrussee/caveman · error

option not found

Error message

option not found

What it means

During the browser `select` action, Act evaluates a JS function over the target <select> element that finds the first option whose value, label, or trimmed text equals the requested option string. If no option matches, the injected function throws "option not found", which the Go driver surfaces as the action error. It exists to fail loudly instead of silently setting a value that does not correspond to any real option.

Solutions

  1. Inspect the target select's options (value and text) and pass an exact match — try the option's `value` attribute first.
  2. Trim/normalize the option string (case, whitespace) to match the DOM text exactly.
  3. Verify Act resolved the intended target element; a wrong selector yields a select with no matching options.
  4. If the select is populated asynchronously, wait for the options to render before issuing the select action.

Example fix

// before
Act(ctx, Action{Kind: "select", Text: "United States"})
// after
Act(ctx, Action{Kind: "select", Text: "US"}) // exact option value/label from the DOM
Defensive patterns

Strategy: validation

Validate before calling

const ok = await page.evaluate((sel, wanted) => {
  const el = document.querySelector(sel);
  if (!el || el.tagName !== 'SELECT') return false;
  return Array.from(el.options).some(o => o.value === wanted || o.label === wanted || o.textContent.trim() === wanted);
}, selector, option);
if (!ok) throw new Error(`option '${option}' not present in ${selector}`);

Prevention

When it happens

Trigger: Calling Act with a select action whose option (or fallback req.Text) does not exactly match any option's value, label, or textContent on the target <select> element. The comparison is exact string equality — case, whitespace, and leading/trailing spaces matter.

Common situations: Passing a human-readable label ('United States') when the option value is a code ('US') and the label text differs slightly; copying option text that contains hidden whitespace or non-breaking spaces; the page re-rendering the select after load so options differ from what the caller assumed; targeting the wrong element so `this.options` is empty.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/168a2559bd719ab0. Report an issue: GitHub.

Appendix: source

Thrown at browse/cdp.go:207

		})); err != nil {
			return ActionResult{OK: false, Settled: false}, err
		}
		return dispatchedAction(), nil
	case "select":
		if err := d.scrollIntoView(runCtx, target); err != nil {
			return ActionResult{OK: false, Settled: false}, err
		}
		if _, _, err := d.waitActionable(runCtx, target); err != nil {
			return ActionResult{OK: false, Settled: false}, err
		}
		option := req.Option
		if option == "" {
			option = req.Text
		}
		if option == "" {
			return ActionResult{OK: false, Settled: false}, errors.New("select: missing option")
		}
		if err := d.callOnNode(runCtx, target, fmt.Sprintf(`function(){ const wanted = %s; const options = Array.from(this.options || []); const match = options.find(o => o.value === wanted || o.label === wanted || o.textContent.trim() === wanted); if (!match) { throw new Error("option not found"); } this.value = match.value; this.dispatchEvent(new Event("input", {bubbles:true})); this.dispatchEvent(new Event("change", {bubbles:true})); return true; }`, jsString(option))); err != nil {
			return ActionResult{OK: false, Settled: false}, err
		}
		return dispatchedAction(), nil
	case "scroll":
		if err := d.scrollIntoView(runCtx, target); err != nil {
			return ActionResult{OK: false, Settled: false}, err
		}
		if _, _, err := d.waitActionable(runCtx, target); err != nil {
			return ActionResult{OK: false, Settled: false}, err
		}
		return dispatchedAction(), nil
	default:
		return ActionResult{OK: false, Settled: false}, fmt.Errorf("unknown action: %s", req.Action)
	}
}

func dispatchedAction() ActionResult {
	// CDP acknowledged dispatch, but asynchronous application state may still be

View on GitHub (pinned to 3ee70a1026)