{"record":{"id":"9ad31b3337246878","repo":"grafana/k6","slug":"q-value-must-be-a-string","errorCode":null,"errorMessage":"%q value must be a string","messagePattern":"%q value must be a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/grpc/params.go","lineNumber":100,"sourceCode":"\trawHeaders, ok := v.(map[string]any)\n\tif !ok {\n\t\treturn md, errors.New(\"must be an object with key-value pairs\")\n\t}\n\n\tfor hk, kv := range rawHeaders {\n\t\tvar val string\n\t\t// The gRPC spec defines that Binary-valued keys end in -bin\n\t\t// https://grpc.io/docs/what-is-grpc/core-concepts/#metadata\n\t\tif strings.HasSuffix(hk, \"-bin\") {\n\t\t\tvar binVal []byte\n\t\t\tif binVal, ok = kv.([]byte); !ok {\n\t\t\t\treturn md, fmt.Errorf(\"%q value must be binary\", hk)\n\t\t\t}\n\n\t\t\t// https://github.com/grpc/grpc-go/blob/v1.57.0/Documentation/grpc-metadata.md#storing-binary-data-in-metadata\n\t\t\tval = string(binVal)\n\t\t} else if val, ok = kv.(string); !ok {\n\t\t\treturn md, fmt.Errorf(\"%q value must be a string\", hk)\n\t\t}\n\n\t\tmd.Append(hk, val)\n\t}\n\n\treturn md, nil\n}\n\n// SetSystemTags sets the system tags for the call.\nfunc (p *callParams) SetSystemTags(state *lib.State, addr string, methodName string) {\n\tif state.Options.SystemTags.Has(metrics.TagURL) {\n\t\tp.TagsAndMeta.SetSystemTagOrMeta(metrics.TagURL, fmt.Sprintf(\"%s%s\", addr, methodName))\n\t}\n\n\tparts := strings.Split(methodName[1:], \"/\")\n\tp.TagsAndMeta.SetSystemTagOrMetaIfEnabled(state.Options.SystemTags, metrics.TagService, parts[0])\n\tp.TagsAndMeta.SetSystemTagOrMetaIfEnabled(state.Options.SystemTags, metrics.TagMethod, parts[1])\n","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/grpc/params.go#L82-L118","documentation":"Metadata keys that do not end in -bin must map to string values; newMetadata asserts the exported JS value is a Go string (params.go:99). Numbers, booleans, objects, arrays or null on a normal key throw '%q value must be a string'.","triggerScenarios":"{ 'x-user-id': 42 }; { active: true }; { user: { id: 1 } }; { ref: null }.","commonSituations":"Sending numeric IDs or flags as metadata without stringifying; spreading parsed JSON directly into metadata objects.","solutions":["Stringify scalars: String(42), String(true)","For genuinely binary data, rename the key with a -bin suffix and pass a Uint8Array"],"exampleFix":"// before\n{ metadata: { 'x-user-id': 42 } }\n\n// after\n{ metadata: { 'x-user-id': '42' } }","handlingStrategy":"type-guard","validationCode":"for (const [k, v] of Object.entries(params.metadata || {})) {\n  if (!k.endsWith('-bin') && typeof v !== 'string') {\n    throw new Error(`metadata['${k}'] must be a string, got ${typeof v}`);\n  }\n}\nclient.invoke(method, req, params);","typeGuard":"function isStringMetadataValue(key, v) {\n  return key.endsWith('-bin') ? v instanceof Uint8Array : typeof v === 'string';\n}","tryCatchPattern":null,"preventionTips":["Stringify numbers and booleans before adding them to metadata","If a value is genuinely binary, rename the key with a -bin suffix and use a Uint8Array","Avoid spreading untyped JSON payloads into metadata"],"tags":["grpc","metadata","type-error"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}