JuliusBrussee/caveman · error
select: missing option
Error message
select: missing option
What it means
The browse CDP driver's Act 'select' action requires an option value: it reads req.Option, falling back to req.Text, and if both are empty it fails closed with 'select: missing option' rather than dispatching a meaningless JS selection. The subsequent injected script only selects an option whose value, label, or trimmed text equals the wanted string.
Solutions
- Populate req.Option with the target <option>'s value (or its visible text) before dispatching the select action
- Alternatively set req.Text to the option's visible label if you only know the text
- Validate the select's options in the page first (via JS evaluation) to get an exact value/label match
- Return a clearer tool-schema error upstream so empty selections are rejected before reaching the driver
Example fix
// before
req := ActRequest{Action: "select"} // Option and Text empty
// after
req := ActRequest{Action: "select", Option: "california"} Defensive patterns
Strategy: validation
Validate before calling
def build_select_request(value: str | None, text: str | None) -> dict:
if not value and not text:
raise ValueError("select requires an option value or text")
return {"action": "select", "option": value or "", "text": text or ""} Type guard
func validSelectTarget(req ActRequest) bool {
return req.Option != "" || req.Text != ""
} Prevention
- Always populate Option (or at least Text) when issuing a select action
- Fetch the <select>'s options first and use an exact value for reliability
- Reject empty selections at the tool/MCP schema layer before they reach the driver
- Prefer matching by value; text matching depends on exact label/trimmed textContent
When it happens
Trigger: Calling the driver's Act with action type 'select' and leaving both Option and Text fields as empty strings on the request struct; no option is sent, so the guard raises before any CDP callOnNode dispatch.
Common situations: Marshalling an MCP/tool payload where the 'option' key was omitted or empty; a caller built the request programmatically and forgot to copy the desired value; an upstream tool mapped a null selection to an empty string instead of rejecting earlier.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- box model has no quad
- browser returned no result object
- kms: plaintext is empty
- missing backend DOM node id
- no named tools found
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/69d218e87c55f8c6.
Report an issue: GitHub.
Appendix: source
Thrown at browse/cdp.go:205
if err := chromedp.Run(runCtx, chromedp.ActionFunc(func(actionCtx context.Context) error {
return input.InsertText(req.Text).Do(actionCtx)
})); 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)
}
}
View on GitHub (pinned to 3ee70a1026)