grafana/k6 · error
options: expected object, got %T
Error message
options: expected object, got %T
What it means
Defensive branch inside ConvertSelectOptionValues: the values argument exported as a Go map kind, but sobek could not export it into map[string]any. Plain JavaScript object literals always export cleanly, so this guards non-standard map-like values (objects from native bindings, Proxy-wrapped objects, or corrupted runtime values). The rejection surfaces as 'parsing select option values: options: expected object, got <type>'.
Source
Thrown at internal/js/modules/k6/browser/browser/mapping.go:89
*valOpt.Value = item
labelOpt := common.SelectOption{Label: new(string)}
*labelOpt.Label = item
opts = append(opts, &valOpt, &labelOpt)
case map[string]any:
opt, err := extractSelectOptionFromMap(item)
if err != nil {
return nil, err
}
opts = append(opts, opt)
default:
return nil, fmt.Errorf("options: expected string or object, got %T", item)
}
}
case reflect.Map:
var raw map[string]any
if err := rt.ExportTo(values, &raw); err != nil {
return nil, fmt.Errorf("options: expected object, got %T", values)
}
opt, err := extractSelectOptionFromMap(raw)
if err != nil {
return nil, err
}
opts = append(opts, opt)
case reflect.TypeFor[*common.ElementHandle]().Kind():
opts = append(opts, t.(*common.ElementHandle)) //nolint:forcetypeassert
case reflect.TypeFor[sobek.Object]().Kind():
obj := values.ToObject(rt)
opt := common.SelectOption{}
for _, k := range obj.Keys() {
switch k {
case "value":
opt.Value = new(string)
*opt.Value = obj.Get(k).String()View on GitHub (pinned to 93accf6570)
Solutions
- Pass a plain object literal: selectOption({ value: 'red' })
- Rebuild descriptors from primitives: { value: String(obj.value), label: String(obj.label) }
- Avoid Proxy or class instances in the values slot
- Report reproducible cases to the k6 browser module
Example fix
// before
await page.locator('select').selectOption(proxyDescriptor);
// after
await page.locator('select').selectOption({ value: String(proxyDescriptor.value) }); Defensive patterns
Strategy: type-guard
Validate before calling
function toPlainDescriptor(v) {
if (typeof v !== 'object' || v === null || Array.isArray(v)) {
throw new TypeError(`selectOption descriptor must be a plain object, got ${typeof v}`);
}
const o = {};
if ('value' in v && v.value !== undefined) o.value = String(v.value);
if ('label' in v && v.label !== undefined) o.label = String(v.label);
if ('index' in v && v.index !== undefined) o.index = Number(v.index);
return o;
} Type guard
function isPlainSelectDescriptor(v) {
return typeof v === 'object' && v !== null &&
Object.getPrototypeOf(v) === Object.prototype;
} Try / catch
try {
await locator.selectOption(descriptor, opts);
} catch (e) {
if (/expected object/.test(String(e.message))) {
await locator.selectOption({ value: String(descriptor?.value ?? '') }, opts);
} else {
throw e;
}
} Prevention
- Build descriptors as plain object literals
- Avoid Proxy/class instances in the values slot
- Rebuild descriptors field-by-field from primitives
When it happens
Trigger: Passing a map-typed sobek value that is not a plain object literal as selectOption's single descriptor, e.g. an object produced by a Go/xk6 extension or a Proxy whose export fails.
Common situations: Interop with xk6 extensions supplying option descriptors; runtime/sobek upgrades altering export semantics.
Related errors
- options: expected array, got %T
- parsing select option values: %w
- options: expected string or object, got %T
- options: unsupported type %T
- options[%v]: expected string, got %T
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/c70c1b7059000f55.
Report an issue: GitHub.