grafana/k6 · error
invalid type %T, expected string, []byte or ArrayBuffer
Error message
invalid type %T, expected string, []byte or ArrayBuffer
What it means
webcrypto's ToBytes helper coerces raw key material and payload arguments. k6 only accepts strings, Go []byte values, and sobek.ArrayBuffer objects; anything else (number, null, plain object, DataView, BigInt, function) reaches the default branch and raises this TypeError-style error naming the offending Go type.
Source
Thrown at internal/js/modules/k6/webcrypto/types.go:35
// byteLength is a type alias for the length of a byte slice.
type byteLength int
// asBitLength returns the length of the byte slice in bits.
func (b byteLength) asBitLength() bitLength {
return bitLength(b) * 8
}
// ToBytes tries to return a byte slice from compatible types.
func ToBytes(data any) ([]byte, error) {
switch dt := data.(type) {
case []byte:
return dt, nil
case string:
return []byte(dt), nil
case sobek.ArrayBuffer:
return dt.Bytes(), nil
default:
return nil, fmt.Errorf("invalid type %T, expected string, []byte or ArrayBuffer", data)
}
}
View on GitHub (pinned to 93accf6570)
Solutions
- Convert the value to a string or ArrayBuffer before the call: String(x), x.toString(), or buffer.slice(0) for ArrayBuffers
- Replace DataView inputs with their underlying ArrayBuffer: dv.buffer
- For JSON data, JSON.stringify the object instead of passing it directly
- If the value may legitimately be absent, guard with a default: data ?? ''
Example fix
// before
const ct = await crypto.subtle.encrypt(alg, key, jsonDataObj); // object -> invalid type map[string]interface {}
// after
const ct = await crypto.subtle.encrypt(alg, key, JSON.stringify(jsonDataObj));
// or: new TextEncoder().encode(JSON.stringify(jsonDataObj)) for explicit bytes Defensive patterns
Strategy: type-guard
Validate before calling
function toCryptoBytes(v) {
if (typeof v === 'string') return v;
if (v instanceof ArrayBuffer) return v;
if (ArrayBuffer.isView(v)) return v.buffer; // DataView/TypedArray -> its ArrayBuffer
throw new Error(`unsupported crypto input: ${typeof v}`);
}
await crypto.subtle.encrypt(alg, key, toCryptoBytes(data)); Type guard
const isCryptoBytes = v => typeof v === 'string' || v instanceof ArrayBuffer; // TypedArrays whose export is []byte are fine too; DataView must be converted: const okInput = v => typeof v === 'string' || v instanceof ArrayBuffer || (ArrayBuffer.isView(v) && v.constructor.name === 'Uint8Array');
Try / catch
try { await crypto.subtle.encrypt(alg, key, data); }
catch (e) { if (/invalid type/.test(e.message)) throw new TypeError(`encrypt payload must be string/ArrayBuffer, got ${typeof data}`); throw e; } Prevention
- Establish one boundary helper (toBytes) at the top of the script and route all crypto inputs through it
- Prefer TextEncoder().encode() for strings when you want explicit bytes
- JSON.stringify objects before hashing/encrypting; never pass parsed JSON directly
- Null-check data coming from network/parse steps before it reaches crypto APIs
When it happens
Trigger: Passing a non-buffer first argument to crypto.subtle.encrypt/decrypt/sign/verify/deriveBits/deriveKey or importKey('raw'|'jwk', ...), e.g. importKey('raw', 42, ...), encrypt(alg, key, {data:...}), or a DataView/JSON object instead of a string/ArrayBuffer. Note DataView is NOT in the accepted list even though ArrayBuffer is.
Common situations: Passing a parsed JSON object where the code meant obj.password (a string); passing a DataView created from a buffer; passing null after a failed upstream fetch/parse; assuming numbers are coerced to strings like in console.log; passing a TypedArray of a wide element type whose export is not []byte.
Related errors
- Unexpected end of selector while parsing selector `${selecto
- Error while parsing selector `${selector}`: ${e.message}
- Error while parsing selector `${selector}` - cannot use ${op
- Error while parsing selector `${selector}` - selector cannot
- k6/experimental/webcrypto has been graduated and it's now gl
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/80dd296d830a5957.
Report an issue: GitHub.