grafana/k6 · critical

parsing options from script got error while parsing %q: %w

Error message

parsing options from script got error while parsing %q: %w

What it means

When exported options decode into lib.Options with a value of the wrong JSON type (json.UnmarshalTypeError), beautifyOptionsJSONUnmarshalError re-runs the parse, extracts the offending line from the pretty-printed options JSON, and shows it in quotes with the underlying type error. The run aborts with AbortedByScriptError / exit code 104 (InvalidConfig).

Source

Thrown at internal/js/bundle.go:252

		return err
	}

	if len(b.callableExports) == 0 {
		return errors.New("no exported functions in script")
	}

	return nil
}

func beautifyOptionsJSONUnmarshalError(data []byte, err error) error {
	unmarshalTypError := new(json.UnmarshalTypeError)
	if errors.As(err, &unmarshalTypError) {
		e := unmarshalTypError
		previousNewLineIndex := max(bytes.LastIndexByte(data[:e.Offset], '\n'), 0)
		nextNewLineIndex := max(min(bytes.IndexByte(data[e.Offset:], '\n'), len(data)-1), (int)(e.Offset))

		info := strings.TrimSpace(string(data[previousNewLineIndex:nextNewLineIndex]))
		err = fmt.Errorf("parsing options from script got error while parsing %q: %w", info, e)
	}
	return err
}

// Instantiate creates a new runtime from this bundle.
func (b *Bundle) Instantiate(ctx context.Context, vuID uint64) (*BundleInstance, error) {
	// Instantiate the bundle into a new VM using a bound init context. This uses a context with a
	// runtime, but no state, to allow module-provided types to function within the init context.
	vuImpl := &moduleVUImpl{
		ctx:     ctx,
		runtime: sobek.New(),
		events: events{
			global: b.preInitState.Events,
			local:  event.NewEventSystem(100, b.preInitState.Logger),
		},
	}
	vuImpl.eventLoop = eventloop.New(vuImpl)
	bi, err := b.instantiate(vuImpl, vuID)

View on GitHub (pinned to 93accf6570)

Solutions

  1. Look at the quoted fragment in the message - it is the exact line of the marshaled options that failed; fix that value's type
  2. Use quoted strings with units for every duration (duration, gracefulStop, gracefulRampDown) and plain numbers for vus/iterations/rate
  3. Keep thresholds, hosts, and executor options as objects/arrays, never strings
  4. Pre-flight check in CI: `k6 inspect script.js` parses options without generating load

Example fix

// before: duration as number -> type error
export const options = { vus: 2, duration: 30 };

// after: duration as a unit string
export const options = { vus: 2, duration: '30s' };
Defensive patterns

Strategy: validation

Validate before calling

# CI pre-flight: k6 inspect parses exported options and exits non-zero on type errors
k6 inspect script.js > /dev/null || exit 1

Prevention

When it happens

Trigger: A recognized option key holding the wrong value type: duration: 30 (must be the string '30s'), vus: '10' (must be a number), iterations: true, thresholds: 'p(95)<200' (must be an object), hosts given as an array instead of an object of host overrides.

Common situations: Options assembled from templates or environment variables where everything becomes a string; porting YAML/JSON config into a JS export; durations written as bare numbers by mistake.

Related errors


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