grafana/k6 · error
unmarshalling options for SDK: %w
Error message
unmarshalling options for SDK: %w
What it means
Client.StartLocalExecution (internal/cloudapi/provisioning/api.go:201) adapts the caller-supplied req.Options (json.RawMessage of pre-marshalled lib.Options) into map[string]any for the generated OpenAPI SDK. This error means that payload is not valid JSON, so the request can never be built.
Source
Thrown at internal/cloudapi/provisioning/api.go:201
}
}
// StartLocalExecution starts a local-execution test run via the
// provisioning API. It generates a K6-Idempotency-Key header for
// safe retries. The caller provides options as pre-marshalled JSON.
func (c *Client) StartLocalExecution(
ctx context.Context, loadTestID int64, req StartLocalExecutionRequest,
) (*StartLocalExecutionResponse, error) {
// Generate idempotency key: 8 random bytes hex-encoded (16 chars).
var key [8]byte
if _, err := rand.Read(key[:]); err != nil {
return nil, fmt.Errorf("generating idempotency key: %w", err)
}
// SDK adapter: unmarshal json.RawMessage → map[string]any.
var opts map[string]any
if err := json.Unmarshal(req.Options, &opts); err != nil {
return nil, fmt.Errorf("unmarshalling options for SDK: %w", err)
}
maxVUs, err := toInt32(req.MaxVUs)
if err != nil {
return nil, fmt.Errorf("max_vus: %w", err)
}
totalDuration, err := toInt32(req.TotalDuration)
if err != nil {
return nil, fmt.Errorf("total_duration: %w", err)
}
sdkReq := k6cloud.NewStartLocalExecutionTestRequest(opts, maxVUs, totalDuration)
if req.ArchiveSize > 0 {
v, err := toInt32(req.ArchiveSize)
if err != nil {
return nil, fmt.Errorf("archive_size: %w", err)
}View on GitHub (pinned to 93accf6570)
Solutions
- Pass Options verbatim from json.Marshal(opts) of lib.Options
- Pre-validate with json.Valid(req.Options) before calling StartLocalExecution
- Log the offending payload (truncated) when the error fires to find the producer
- If it comes from k6 itself rather than custom code, report a k6 bug
Example fix
// before
req := provisioning.StartLocalExecutionRequest{
Options: json.RawMessage(`{"vus":`), // truncated / invalid JSON
}
// after
b, err := json.Marshal(libOpts)
if err != nil {
return err
}
req := provisioning.StartLocalExecutionRequest{Options: b} Defensive patterns
Strategy: validation
Validate before calling
if !json.Valid(req.Options) {
return fmt.Errorf("options payload is not valid JSON (%d bytes)", len(req.Options))
} Type guard
func isValidOptionsJSON(raw json.RawMessage) bool {
return json.Valid(raw)
} Try / catch
if err := client.StartLocalExecution(ctx, id, req); err != nil {
if strings.Contains(err.Error(), "unmarshalling options") {
log.Printf("options payload corrupt: %q", truncate(req.Options, 256))
}
return err
} Prevention
- Always build Options with json.Marshal(lib.Options) and pass the result verbatim
- Add json.Valid checks in tests that hand-construct StartLocalExecutionRequest
- Never hand-concatenate JSON for this field
When it happens
Trigger: StartLocalExecutionRequest.Options populated with hand-built, truncated, or empty bytes instead of the output of json.Marshal(lib.Options); upstream marshalling produced corrupt output; a test fixture contains malformed JSON.
Common situations: Custom code paths or tests that construct StartLocalExecutionRequest directly instead of going through cmd's marshalling of lib.Options; version skew where the Options marshalling format changed unexpectedly.
Related errors
- invalid metric type
- invalid value type
- error parsing script options: %w
- unmarshaling %q to ReducedMotion: %w
- unmarshaling %q to ColorScheme: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/b8f9e4291257aef9.
Report an issue: GitHub.