{"record":{"id":"e2eaa3bb5badd4df","repo":"grafana/k6","slug":"reading-value-w","errorCode":null,"errorMessage":"reading value: %w","messagePattern":"reading value: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":1740,"sourceCode":"\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn nil, errorFromDOMError(err)\n\t}\n\tselectHandle, ok := v.(jsHandle)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected select element type %T\", v)\n\t}\n\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.","sourceCodeStart":1722,"sourceCodeEnd":1758,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L1722-L1758","documentation":"While converting the selected <option> handles into strings, k6 calls JSONValue() on each option handle; failure is reported as 'reading value: <cause>'. This means the option handle became invalid (its execution context or remote object was released) before its value could be serialized.","triggerScenarios":"The <select> is rebuilt (framework re-render) between selection and value readback, invalidating option remote objects; navigation destroys the context; the handle was already disposed due to the page state changing mid-loop.","commonSituations":"React/Vue controlled selects that re-render options after change events; option elements removed by virtual DOM diffing; slow pages where the readback exceeds object lifetime.","solutions":["Re-select after the DOM settles: wait for the framework render to finish (waitForTimeout or a predicate) before selectOption.","Read values defensively afterwards with evaluate(() => select.selectedOptions.map(o => o.value)) instead of relying on the return value.","If the framework replaces options on change, set the value programmatically and dispatch the event yourself."],"exampleFix":"// before\nconst vals = await page.selectOption('#sel', 'x'); // re-render invalidates options\n\n// after\nawait page.selectOption('#sel', 'x').catch(() => null);\nconst vals = await page.evaluate(() =>\n  [...document.querySelector('#sel').selectedOptions].map(o => o.value));","handlingStrategy":"fallback","validationCode":"await page.waitForFunction(() => !document.querySelector('#sel')?.disabled);","typeGuard":null,"tryCatchPattern":"try { return await page.selectOption(sel, v); }\ncatch (e) {\n  if (/reading value/.test(e.message)) {\n    return page.evaluate(() => [...document.querySelector(sel).selectedOptions].map(o => o.value));\n  }\n  throw e;\n}","preventionTips":["Let framework re-renders finish before selecting (wait a tick or a predicate)","For controlled selects, set value via evaluate and dispatch change yourself","Do not depend on selectOption's return value on pages that mutate options"],"tags":["browser","select","handle-lifetime","re-render","serialization"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}