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

  1. Wrap bytes in a typed array: new Uint8Array([2, 200])
  2. Or decode base64 first: encoding.b64decode(s) from 'k6/encoding' returns an ArrayBuffer, which is accepted
  3. 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

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


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/264abc34107ce132. Report an issue: GitHub.