{"record":{"id":"67cea23683c8baf1","repo":"grafana/k6","slug":"selecthandle-dispose-w","errorCode":null,"errorMessage":"selectHandle.dispose: %w","messagePattern":"selectHandle\\.dispose: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":1748,"sourceCode":"\n\t// pack the selected <option> values inside <select> into a slice\n\toptHandles, err := selectHandle.getProperties()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getProperties: %w\", err)\n\t}\n\tvals := make([]string, 0, len(optHandles))\n\tfor _, oh := range optHandles {\n\t\tval, err := oh.JSONValue()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"reading value: %w\", err)\n\t\t}\n\t\tvals = append(vals, val)\n\t\tif err := oh.dispose(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"optionHandle.dispose: %w\", err)\n\t\t}\n\t}\n\tif err := selectHandle.dispose(); err != nil {\n\t\treturn nil, fmt.Errorf(\"selectHandle.dispose: %w\", err)\n\t}\n\n\treturn vals, nil\n}\n\n// SetContent replaces the entire HTML document content.\nfunc (f *Frame) SetContent(html string, _ *FrameSetContentOptions) error {\n\tf.log.Debugf(\"Frame:SetContent\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\t// TODO(@inancgumus): Respect the FrameSetContentOptions before executing the action.\n\t// A solution is similar to the logic in `WaitForLoadState`.\n\n\tjs := `(html) => {\n\t\twindow.stop();\n\t\tdocument.open();\n\t\tdocument.write(html);\n\t\tdocument.close();\n\t}`","sourceCodeStart":1730,"sourceCodeEnd":1766,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L1730-L1766","documentation":"The final step of Frame.selectOption's readback disposes the JSHandle wrapping the array of selected options; failure is wrapped as 'selectHandle.dispose: <cause>'. Like 807, the selection succeeded and values were already collected — only releasing the array handle failed, typically because its context died mid-operation.","triggerScenarios":"Navigation or context destruction between reading option values and disposing the array handle; CDP session torn down (page close, browser crash) during the final cleanup call.","commonSituations":"onchange handlers triggering navigation/submit; test teardown closing the browser concurrently with the last selectOption; usually intermittent.","solutions":["Treat as retryable: verify the selection with evaluate and move on if the dispose fails after values were read.","Serialize teardown — do not call page.close()/browser.close() from another async branch while actions are in flight.","If persistent, upgrade k6 to pick up selectOption readback fixes."],"exampleFix":"// before\nlet v;\ntry { v = await page.selectOption('#sel', 'x'); } catch (e) { throw e; }\n\n// after\nlet v;\ntry { v = await page.selectOption('#sel', 'x'); }\ncatch (e) {\n  v = await page.evaluate(() => [...document.querySelector('#sel').selectedOptions].map(o => o.value));\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return await page.selectOption(sel, v); }\ncatch (e) {\n  if (/selectHandle\\.dispose/.test(e.message)) {\n    return page.evaluate(() => [...document.querySelector(sel).selectedOptions].map(o => o.value));\n  }\n  throw e;\n}","preventionTips":["Serialize teardown: no concurrent page.close() while actions run","Verify selection via evaluate when dispose races occur","Keep k6 current to benefit from readback fixes"],"tags":["browser","select","cleanup","cdp","lifecycle"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}