grafana/k6 · error

max_vus

Error message

max_vus: %w

What it means

Returned by Client.StartLocalExecution (internal/cloudapi/provisioning/api.go:206) when req.MaxVUs (int64) does not fit in int32, because the underlying cloud SDK models max_vus as int32 (toInt32 at api.go:296-301 rejects anything outside [-2147483648, 2147483647]). A VU count above 2,147,483,647 is far beyond any executable load, so in practice this signals garbage input (overflow/negative sentinel) rather than an ambitious test.

Solutions

  1. Check how the caller computes MaxVUs (usually lib.Options.Scenarios VU totals in cmd) and clamp or fail earlier on unreasonable values.
  2. Replace int sentinel values like -1 with a real count before constructing the request.
  3. Validate 0 < MaxVUs <= 2_000_000 (k6 Cloud's practical ceiling) before calling StartLocalExecution.

Example fix

// before
resp, err := c.StartLocalExecution(ctx, id, provisioning.StartLocalExecutionRequest{MaxVUs: computedMaxVUs})

// after
if req.MaxVUs <= 0 || req.MaxVUs > 2_000_000 {
	return fmt.Errorf("max_vus %d out of supported range (1..2000000)", req.MaxVUs)
}
resp, err := c.StartLocalExecution(ctx, id, provisioning.StartLocalExecutionRequest{MaxVUs: computedMaxVUs})
Defensive patterns

Strategy: validation

Validate before calling

const maxCloudVUs = int64(2_000_000) // practical k6 Cloud ceiling, far under int32

func validMaxVUs(v int64) bool {
	return v > 0 && v <= maxCloudVUs
}

if !validMaxVUs(req.MaxVUs) {
	return fmt.Errorf("max_vus %d outside supported range 1..%d", req.MaxVUs, maxCloudVUs)
}

Try / catch

if _, err := c.StartLocalExecution(ctx, id, req); err != nil {
	if strings.Contains(err.Error(), "max_vus") && strings.Contains(err.Error(), "overflows int32") {
		// input bug, not transient: fix how MaxVUs is computed (sentinels/units)
		return fmt.Errorf("computed max_vus=%d is invalid; check scenario VU totals", req.MaxVUs)
	}
}

Prevention

When it happens

Trigger: StartLocalExecutionRequest.MaxVUs > math.MaxInt32 (or < math.MinInt32): usually an uninitialized/negative value used as a sentinel, or a computed sum over overflowing from a misconfigured options structure.

Common situations: Callers deriving MaxVUs via arithmetic on untrusted config; using -1 as 'unknown' marker and forgetting to replace it; tests with absurd fixture numbers.

Related errors


AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18). Data as JSON: /api/errors/0919c4057fe57a3c. Report an issue: GitHub.

Appendix: source

Thrown at internal/cloudapi/provisioning/api.go:206

// 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)
		}
		sdkReq.SetArchiveSize(v)
	} else {
		sdkReq.SetArchiveSizeNil()
	}

View on GitHub (pinned to 01ffac6f24)