{"record":{"id":"04f010d0bc7f37cf","repo":"grafana/k6","slug":"options-v-expected-string-got-t","errorCode":null,"errorMessage":"options[%v]: expected string, got %T","messagePattern":"options\\[(.+?)\\]: expected string, got %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/mapping.go","lineNumber":148,"sourceCode":"\t\t*labelOpt.Label = t.(string) //nolint:forcetypeassert\n\t\topts = append(opts, &valOpt, &labelOpt)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"options: unsupported type %T\", values)\n\t}\n\n\treturn opts, nil\n}\n\nfunc extractSelectOptionFromMap(v map[string]any) (*common.SelectOption, error) {\n\topt := &common.SelectOption{}\n\tfor k, raw := range v {\n\t\tswitch k {\n\t\tcase \"value\":\n\t\t\topt.Value = new(string)\n\n\t\t\tv, ok := raw.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"options[%v]: expected string, got %T\", k, raw)\n\t\t\t}\n\n\t\t\t*opt.Value = v\n\t\tcase \"label\":\n\t\t\topt.Label = new(string)\n\n\t\t\tv, ok := raw.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"options[%v]: expected string, got %T\", k, raw)\n\t\t\t}\n\t\t\t*opt.Label = v\n\t\tcase \"index\":\n\t\t\topt.Index = new(int64)\n\n\t\t\tswitch raw := raw.(type) {\n\t\t\tcase int:\n\t\t\t\t*opt.Index = int64(raw)\n\t\t\tcase int64:","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/grafana/k6/blob/8d06114777191d21ef885d05c5f8aa9e1ed838ae/internal/js/modules/k6/browser/browser/mapping.go#L130-L166","documentation":"Thrown by extractSelectOptionFromMap (browser/mapping.go:140) while parsing a selectOption descriptor object: the 'value' key was present but its value is not a string. k6 requires value-based selection descriptors to be { value: '<string>' }; the type assertion raw.(string) fails for any other Go export type and the offending key name is included in the message.","triggerScenarios":"page.selectOption('#sel', { value: 123 }), { value: true }, or { value: null }. Numeric option values read from JSON without string conversion are the classic case.","commonSituations":"Option values sourced from a JSON/CSV dataset where values are numbers; APIs that return option values as integers; shared option objects reused from URL query building where numbers are common.","solutions":["Quote the value: { value: '123' } or { value: String(optionValue) }.","Coerce at the data boundary: options = rawOptions.map(o => ({ ...o, value: String(o.value) })).","If the option genuinely has no value attribute, match by label ({ label: '...' }) or index ({ index: n }) instead.","Add a runtime check that every descriptor's value field is typeof 'string'."],"exampleFix":"// before\nawait page.selectOption('#sel', { value: data.userId }); // userId = 1001\n\n// after\nawait page.selectOption('#sel', { value: String(data.userId) });","handlingStrategy":"type-guard","validationCode":"const opt = { ...raw };\nif ('value' in opt && typeof opt.value !== 'string') opt.value = String(opt.value);\nawait page.selectOption('#sel', opt);","typeGuard":"function hasStringValue(o) {\n  return !('value' in o) || typeof o.value === 'string';\n}","tryCatchPattern":"try { await page.selectOption('#sel', opt); } catch (e) { if (/options\\[value\\]: expected string/.test(e.message)) { await page.selectOption('#sel', { ...opt, value: String(opt.value) }); } else throw e; }","preventionTips":["Quote value fields in JSON datasets used for selection.","Coerce value to String where data is loaded, not at the call site.","Type descriptors as { value?: string; label?: string; index?: number }."],"tags":["k6","browser","select-option","type-validation","value-key"],"backgroundTag":"invalid-argument-value","analyzedSha":"8d06114777191d21ef885d05c5f8aa9e1ed838ae","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}