grafana/k6 · error
%q value must be binary
Error message
%q value must be binary
What it means
Per the gRPC spec, metadata keys ending in -bin carry binary values. newMetadata type-asserts such values to []byte after exporting them from JS, so a Uint8Array (or ArrayBuffer) is required. Strings, numbers or plain JS arrays for a -bin key throw '%q value must be binary'.
Source
Thrown at internal/js/modules/k6/grpc/params.go:94
if common.IsNullish(input) {
return md, nil
}
v := input.Export()
rawHeaders, ok := v.(map[string]any)
if !ok {
return md, errors.New("must be an object with key-value pairs")
}
for hk, kv := range rawHeaders {
var val string
// The gRPC spec defines that Binary-valued keys end in -bin
// https://grpc.io/docs/what-is-grpc/core-concepts/#metadata
if strings.HasSuffix(hk, "-bin") {
var binVal []byte
if binVal, ok = kv.([]byte); !ok {
return md, fmt.Errorf("%q value must be binary", hk)
}
// https://github.com/grpc/grpc-go/blob/v1.57.0/Documentation/grpc-metadata.md#storing-binary-data-in-metadata
val = string(binVal)
} else if val, ok = kv.(string); !ok {
return md, fmt.Errorf("%q value must be a string", hk)
}
md.Append(hk, val)
}
return md, nil
}
// SetSystemTags sets the system tags for the call.
func (p *callParams) SetSystemTags(state *lib.State, addr string, methodName string) {
if state.Options.SystemTags.Has(metrics.TagURL) {
p.TagsAndMeta.SetSystemTagOrMeta(metrics.TagURL, fmt.Sprintf("%s%s", addr, methodName))View on GitHub (pinned to 93accf6570)
Solutions
- Wrap bytes in a typed array: new Uint8Array([2, 200])
- Or decode base64 first: encoding.b64decode(s) from 'k6/encoding' returns an ArrayBuffer, which is accepted
- Keep -bin suffixes only on keys whose values are genuinely binary
Example fix
// before
{ metadata: { 'x-load-tester-bin': 'buffer' } }
// after
{ metadata: { 'x-load-tester-bin': new Uint8Array([2, 200]) } } Defensive patterns
Strategy: type-guard
Validate before calling
function isBinaryValue(v) {
return v instanceof Uint8Array || v instanceof ArrayBuffer;
}
for (const [k, v] of Object.entries(params.metadata || {})) {
if (k.endsWith('-bin') && !isBinaryValue(v)) {
throw new Error(`metadata['${k}'] must be a Uint8Array/ArrayBuffer`);
}
}
client.invoke(method, req, params); Type guard
function isBinaryMetadataValue(v) {
return v instanceof Uint8Array || v instanceof ArrayBuffer;
} Prevention
- Use new Uint8Array([...]) or encoding.b64decode(...) for -bin keys
- Decode base64 before attaching it to a -bin key
- Do not use plain JS arrays for binary values
When it happens
Trigger: { 'x-load-tester-bin': 'MG==' } (base64 string); { 'session-bin': [2, 200] } (plain Array, not a typed array); numeric values on a -bin key.
Common situations: Encoders returning base64 strings instead of bytes; assuming JSON arrays serialize as binary; porting metadata from grpcurl, which accepts base64 for -bin keys.
Related errors
- invalid metadata param: %w
- %q value must be a string
- invalid reflectMetadata param: %w
- Unexpected end of selector while parsing selector `${selecto
- must be an object with key-value pairs
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/264abc34107ce132.
Report an issue: GitHub.