grafana/k6 · error

converting argument %q in execution context ID %d and frame

Error message

converting argument %q in execution context ID %d and frame ID %v: %w

What it means

While evaluating a script with arguments (page.evaluate / evaluateHandle style calls), k6 converts every argument into a CDP CallArgument via convertArgument (helpers.go:42). Supported values: int64, float64 (with NaN/Infinity/-0 special cases), ElementHandle/BaseJSHandle, and anything json.Marshal can serialize. Values that fail JSON marshaling — functions, cyclic structures, unsupported types — or a leaked sobek.Value ('sobek.Value escaped') produce this error naming the offending argument.

Source

Thrown at internal/js/modules/k6/browser/common/execution_context.go:191

		Do(context.Context) (*runtime.RemoteObject, *runtime.ExceptionDetails, error)
	}

	if !opts.forceCallable {
		if !hasSourceURL(js) {
			js += "\n" + suffix
		}

		action = runtime.Evaluate(js).
			WithContextID(e.id).
			WithReturnByValue(opts.returnByValue).
			WithAwaitPromise(true).
			WithUserGesture(true)
	} else {
		var arguments []*runtime.CallArgument
		for _, arg := range args {
			result, err := convertArgument(apiCtx, e, arg)
			if err != nil {
				return nil, fmt.Errorf("converting argument %q "+
					"in execution context ID %d and frame ID %v: %w",
					arg, e.id, e.Frame().ID(), err)
			}
			arguments = append(arguments, result)
		}

		js += "\n" + suffix + "\n"
		action = runtime.CallFunctionOn(js).
			WithArguments(arguments).
			WithExecutionContextID(e.id).
			WithReturnByValue(opts.returnByValue).
			WithAwaitPromise(true).
			WithUserGesture(true)
	}

	var (
		remoteObject     *runtime.RemoteObject
		exceptionDetails *runtime.ExceptionDetails

View on GitHub (pinned to 93accf6570)

Solutions

  1. Pass only serializable values (strings, numbers, booleans, plain arrays/objects) as arguments
  2. To pass a DOM node, obtain an ElementHandle and pass the handle itself
  3. Strip cycles / project out only needed fields before passing large objects
  4. Double-check argument order: evaluate(fn, ...args)

Example fix

// before
const r = await page.evaluate((cb) => cb(2), (n) => n * 2); // function passed as argument

// after
const r = await page.evaluate((n) => n * 2, 2);
Defensive patterns

Strategy: validation

Validate before calling

function serializable(v) {
  if (v === null) return true;
  const t = typeof v;
  if (t === 'function' || t === 'symbol' || t === 'bigint') return false;
  if (t !== 'object') return true;
  if (Array.isArray(v)) return v.every(serializable);
  return Object.values(v).every(serializable);
}
const args = [1, 'a', { x: 1 }];
if (!args.every(serializable)) throw new Error('non-serializable evaluate argument');
await page.evaluate(fn, ...args);

Type guard

function isPlainArg(v) {
  if (v && typeof v === 'object' && typeof v.click === 'function') return true; // ElementHandle
  return v === null || ['string', 'number', 'boolean', 'undefined'].includes(typeof v);
}

Try / catch

try {
  await page.evaluate(fn, arg);
} catch (e) {
  if (/converting argument/.test(e.message)) {
    // strip functions/cycles from args, or pass an ElementHandle, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a function as an argument instead of it being the evaluated function: page.evaluate((cb) => cb(2), (n) => n * 2); objects with circular references; passing a JSHandle created in a different or already-closed page; any value that cannot be JSON-serialized.

Common situations: Confusing which function is 'the script' versus 'an argument' in evaluate(fn, ...args); sending page-internal objects or k6 module objects as arguments; passing deeply nested or cyclic structures built during the test; handles from a closed page.

Related errors


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