grafana/k6 · error

call to Blob.[arrayBuffer] failed: %w

Error message

call to Blob.[arrayBuffer] failed: %w

What it means

When a Blob is nested inside another Blob's parts, k6 reads its bytes by invoking the inner object's arrayBuffer() method. If that call itself throws (the method was replaced with a throwing stub, or the object is a fake Blob whose method errors), this wrapped error is thrown from inside fillData, typically surfacing as 'failed to process [blobParts]' upstream.

Source

Thrown at internal/js/modules/k6/websockets/helpers.go:51

}

func isBlob(o *sobek.Object, blobConstructor sobek.Value) bool {
	return o.Prototype().Get("constructor") == blobConstructor
}

func isObject(val sobek.Value) bool {
	return val != nil && val.ExportType() != nil && val.ExportType().Kind() == reflect.Map
}

func extractBytes(o *sobek.Object, rt *sobek.Runtime) []byte {
	arrayBuffer, ok := sobek.AssertFunction(o.Get("arrayBuffer"))
	if !ok {
		common.Throw(rt, errors.New("Blob.[arrayBuffer] is not a function"))
	}

	buffer, err := arrayBuffer(sobek.Undefined())
	if err != nil {
		common.Throw(rt, fmt.Errorf("call to Blob.[arrayBuffer] failed: %w", err))
	}

	p, ok := buffer.Export().(*sobek.Promise)
	if !ok {
		common.Throw(rt, errors.New("Blob.[arrayBuffer] return is not a Promise"))
	}

	ab, ok := p.Result().Export().(sobek.ArrayBuffer)
	if !ok {
		common.Throw(rt, errors.New("Blob.[arrayBuffer] promise's return is not an ArrayBuffer"))
	}

	return ab.Bytes()
}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Only nest Blobs created by the WebSocket module's own Blob constructor
  2. Replace mocks with real small Blobs: new ws.Blob(['fixture'])
  3. If you wrap a Blob, keep the original instance and expose it directly rather than reimplementing arrayBuffer()
  4. Inspect the wrapped cause after the colon — it is the exception your fake arrayBuffer raised

Example fix

// before
const fake = { size: 3, arrayBuffer: async () => { throw new Error('not implemented'); } };
const b = new ws.Blob([fake]); // -> call to Blob.[arrayBuffer] failed

// after
const real = new ws.Blob(['fix']);
const b = new ws.Blob([real]);
Defensive patterns

Strategy: type-guard

Validate before calling

const isRealBlob = (p, BlobCtor) => p instanceof BlobCtor;
// before nesting:
const parts = rawParts.map(p => (p && p.arrayBuffer && !isRealBlob(p, WS.Blob)) ? new WS.Blob([String(p)]) : p);
const b = new WS.Blob(parts);

Type guard

const isNestableBlob = (p, BlobCtor) => p instanceof BlobCtor && typeof p.arrayBuffer === 'function';

Try / catch

try { b = new WS.Blob(parts); } catch (e) { if (/arrayBuffer. failed/.test(e.message)) throw new Error('nested fake Blob detected - use real WS.Blob instances'); throw e; }

Prevention

When it happens

Trigger: new ws.Blob([fakeBlob]) where fakeBlob is a hand-made object whose arrayBuffer is not a real function that succeeds, e.g. { arrayBuffer: () => { throw new Error('boom') } }, or a real Blob whose arrayBuffer was monkey-patched. extractBytes calls the method synchronously and propagates any failure with %w.

Common situations: Test doubles/mocks standing in for Blob during unit tests of message building; partial reimplementation of the Blob API in userland helpers; subclass-like wrappers that forward methods but throw on unsupported states. Real Blob instances produced by the same constructor essentially never trigger this.

Related errors


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