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
- Look at the quoted fragment in the message - it is the exact line of the marshaled options that failed; fix that value's type
- Use quoted strings with units for every duration (duration, gracefulStop, gracefulRampDown) and plain numbers for vus/iterations/rate
- Keep thresholds, hosts, and executor options as objects/arrays, never strings
- 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
- Write all durations as unit strings ('30s', '1m') and all counts as numbers
- When options are built from environment variables, coerce explicitly (Number(), String()) before composing
- Run k6 inspect locally before every commit that touches options
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
- unmarshalling options for SDK: %w
- error parsing script options: %w
- marshaling hosts option: %w
- unmarshaling hosts option: %w
- unsupported browser type: %s
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/cd52fe2f15332ae9.
Report an issue: GitHub.