grafana/k6 · error
reading value: %w
Error message
reading value: %w
What it means
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.
Source
Thrown at internal/js/modules/k6/browser/common/frame.go:1740
v, err := call(f.ctx, act, opts.Timeout)
if err != nil {
return nil, errorFromDOMError(err)
}
selectHandle, ok := v.(jsHandle)
if !ok {
return nil, fmt.Errorf("unexpected select element type %T", v)
}
// pack the selected <option> values inside <select> into a slice
optHandles, err := selectHandle.getProperties()
if err != nil {
return nil, fmt.Errorf("getProperties: %w", err)
}
vals := make([]string, 0, len(optHandles))
for _, oh := range optHandles {
val, err := oh.JSONValue()
if err != nil {
return nil, fmt.Errorf("reading value: %w", err)
}
vals = append(vals, val)
if err := oh.dispose(); err != nil {
return nil, fmt.Errorf("optionHandle.dispose: %w", err)
}
}
if err := selectHandle.dispose(); err != nil {
return nil, fmt.Errorf("selectHandle.dispose: %w", err)
}
return vals, nil
}
// SetContent replaces the entire HTML document content.
func (f *Frame) SetContent(html string, _ *FrameSetContentOptions) error {
f.log.Debugf("Frame:SetContent", "fid:%s furl:%q", f.ID(), f.URL())
// TODO(@inancgumus): Respect the FrameSetContentOptions before executing the action.View on GitHub (pinned to 93accf6570)
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.
Example fix
// before
const vals = await page.selectOption('#sel', 'x'); // re-render invalidates options
// after
await page.selectOption('#sel', 'x').catch(() => null);
const vals = await page.evaluate(() =>
[...document.querySelector('#sel').selectedOptions].map(o => o.value)); Defensive patterns
Strategy: fallback
Validate before calling
await page.waitForFunction(() => !document.querySelector('#sel')?.disabled); Try / catch
try { return await page.selectOption(sel, v); }
catch (e) {
if (/reading value/.test(e.message)) {
return page.evaluate(() => [...document.querySelector(sel).selectedOptions].map(o => o.value));
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- dispatching element event %q: %w
- selecting options: %w
- unpacking selected options: %w
- converting argument %q in execution context ID %d and frame
- extracting value from remote object with ID %s: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/e2eaa3bb5badd4df.
Report an issue: GitHub.