grafana/k6 · error · TypeError

SharedArray is immutable

Error message

SharedArray is immutable

What it means

SharedArray wraps a memory-shared, once-initialized array behind a frozen dynamic array so every VU sees the same data without per-VU copies. The Set trap intentionally raises a TypeError on any element assignment (arr[i] = v) — immutability is the contract that makes sharing safe, so writes are rejected, not ignored.

Source

Thrown at internal/js/modules/k6/data/share.go:37

	isFrozen sobek.Callable
	parse    sobek.Callable
}

func (s sharedArray) wrap(rt *sobek.Runtime) sobek.Value {
	freeze, _ := sobek.AssertFunction(rt.GlobalObject().Get("Object").ToObject(rt).Get("freeze"))
	isFrozen, _ := sobek.AssertFunction(rt.GlobalObject().Get("Object").ToObject(rt).Get("isFrozen"))
	parse, _ := sobek.AssertFunction(rt.GlobalObject().Get("JSON").ToObject(rt).Get("parse"))
	return rt.NewDynamicArray(wrappedSharedArray{
		sharedArray: s,
		rt:          rt,
		freeze:      freeze,
		isFrozen:    isFrozen,
		parse:       parse,
	})
}

func (s wrappedSharedArray) Set(_ int, _ sobek.Value) bool {
	panic(s.rt.NewTypeError("SharedArray is immutable")) // this is specifically a type error
}

func (s wrappedSharedArray) SetLen(_ int) bool {
	panic(s.rt.NewTypeError("SharedArray is immutable")) // this is specifically a type error
}

func (s wrappedSharedArray) Get(index int) sobek.Value {
	if index < 0 || index >= len(s.arr) {
		return sobek.Undefined()
	}
	val, err := s.parse(sobek.Undefined(), s.rt.ToValue(s.arr[index]))
	if err != nil {
		common.Throw(s.rt, err)
	}

	err = s.deepFreeze(s.rt, val)
	if err != nil {
		common.Throw(s.rt, err)

View on GitHub (pinned to 93accf6570)

Solutions

  1. Mutate a per-VU copy instead: const local = Array.from(data) (or data.map(x => JSON.parse(JSON.stringify(x)))) then modify local
  2. Track per-iteration state in a separate plain array or a vu-level variable, keyed by index
  3. If you need write-once-then-share semantics, build the final data inside the SharedArray initializer function itself
  4. Use in-place-safe helpers: copy before sort/shuffle (const sorted = [...local].sort())

Example fix

// before
const users = new SharedArray('users', () => loadUsers());
export default function () { users[0] = 'taken'; } // TypeError: SharedArray is immutable

// after
const users = new SharedArray('users', () => loadUsers());
export default function () {
  const taken = Array.from(users); // private per-VU copy
  taken[0] = 'taken';
}
Defensive patterns

Strategy: fallback

Validate before calling

// treat SharedArray as read-only; copy before any mutation
const writable = (shared) => Array.from(shared);
const local = writable(data);
local[0] = 'taken'; // safe

Type guard

// k6 >= 0.5x: SharedArray instances can be detected by tag
const isShared = a => a && Object.prototype.toString.call(a) === '[object SharedArray]'; // if exposed; otherwise track via instanceof/constructor at creation site

Prevention

When it happens

Trigger: const data = new SharedArray('data', () => [...]); then data[0] = 'x', data[i] = obj inside a VU function, or any indexed write (including via destructuring-style helpers that assign back). Only reads and JSON.parse-on-read (Get) are implemented; there is no code path that permits element mutation.

Common situations: Marking test data as 'used' (data[i].seen = true or data[i] = null) — impossible by design; sharing arrays between iterations and trying to update state per iteration; porting plain-array test data to SharedArray for memory savings and forgetting to remove in-place shuffles/marks; helper libraries (shuffle, uniq) that sort/assign in place.

Related errors


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