{"record":{"id":"69d218e87c55f8c6","repo":"JuliusBrussee/caveman","slug":"select-missing-option","errorCode":null,"errorMessage":"select: missing option","messagePattern":"select: missing option","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"browse/cdp.go","lineNumber":205,"sourceCode":"\t\tif err := chromedp.Run(runCtx, chromedp.ActionFunc(func(actionCtx context.Context) error {\n\t\t\treturn input.InsertText(req.Text).Do(actionCtx)\n\t\t})); err != nil {\n\t\t\treturn ActionResult{OK: false, Settled: false}, err\n\t\t}\n\t\treturn dispatchedAction(), nil\n\tcase \"select\":\n\t\tif err := d.scrollIntoView(runCtx, target); err != nil {\n\t\t\treturn ActionResult{OK: false, Settled: false}, err\n\t\t}\n\t\tif _, _, err := d.waitActionable(runCtx, target); err != nil {\n\t\t\treturn ActionResult{OK: false, Settled: false}, err\n\t\t}\n\t\toption := req.Option\n\t\tif option == \"\" {\n\t\t\toption = req.Text\n\t\t}\n\t\tif option == \"\" {\n\t\t\treturn ActionResult{OK: false, Settled: false}, errors.New(\"select: missing option\")\n\t\t}\n\t\tif 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 {\n\t\t\treturn ActionResult{OK: false, Settled: false}, err\n\t\t}\n\t\treturn dispatchedAction(), nil\n\tcase \"scroll\":\n\t\tif err := d.scrollIntoView(runCtx, target); err != nil {\n\t\t\treturn ActionResult{OK: false, Settled: false}, err\n\t\t}\n\t\tif _, _, err := d.waitActionable(runCtx, target); err != nil {\n\t\t\treturn ActionResult{OK: false, Settled: false}, err\n\t\t}\n\t\treturn dispatchedAction(), nil\n\tdefault:\n\t\treturn ActionResult{OK: false, Settled: false}, fmt.Errorf(\"unknown action: %s\", req.Action)\n\t}\n}\n","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/browse/cdp.go#L187-L223","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nreq := ActRequest{Action: \"select\"} // Option and Text empty\n// after\nreq := ActRequest{Action: \"select\", Option: \"california\"}","handlingStrategy":"validation","validationCode":"def build_select_request(value: str | None, text: str | None) -> dict:\n    if not value and not text:\n        raise ValueError(\"select requires an option value or text\")\n    return {\"action\": \"select\", \"option\": value or \"\", \"text\": text or \"\"}","typeGuard":"func validSelectTarget(req ActRequest) bool {\n    return req.Option != \"\" || req.Text != \"\"\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["browser-automation","cdp","validation","empty-input"],"backgroundTag":"empty-required-field","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}