grafana/k6 · error

total_duration

Error message

total_duration: %w

What it means

Returned by Client.StartLocalExecution (internal/cloudapi/provisioning/api.go:210) when req.TotalDuration (seconds, int64) does not fit in int32 as required by the cloud SDK's model. int32 max is 2,147,483,647 seconds ≈ 68 years, so a legitimate duration never triggers this — it means the caller passed a negative sentinel or a corrupted/overflowed value where a test length in seconds was expected.

Solutions

  1. Verify the caller computes TotalDuration as the max scenario end time in seconds (e.g. via lib.Options.Scenarios getDurations), not nanoseconds.
  2. Replace -1/zero sentinels with the real computed duration before building the request.
  3. Sanity-bound the value (say 1..315,360,000 seconds ≈ 10 years) before calling.

Example fix

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

// after — assert sane seconds range before the call
const maxReasonableSeconds = 31536000 // 1 year
if req.TotalDuration <= 0 || req.TotalDuration > maxReasonableSeconds {
	return fmt.Errorf("total_duration %ds out of range (1..%d)", req.TotalDuration, maxReasonableSeconds)
}
resp, err := c.StartLocalExecution(ctx, id, provisioning.StartLocalExecutionRequest{TotalDuration: totalDur})
Defensive patterns

Strategy: validation

Validate before calling

const maxReasonableDurationSeconds = int64(31536000) // one year

func validTotalDuration(v int64) bool {
	return v > 0 && v <= maxReasonableDurationSeconds
}

if !validTotalDuration(req.TotalDuration) {
	return fmt.Errorf("total_duration %ds outside supported range", req.TotalDuration)
}

Try / catch

if _, err := c.StartLocalExecution(ctx, id, req); err != nil {
	if strings.Contains(err.Error(), "total_duration") && strings.Contains(err.Error(), "overflows int32") {
		// almost certainly a unit bug (ns vs s) — fix the computation, do not retry
		return fmt.Errorf("total_duration=%ds implausible; verify scenario duration summation units", req.TotalDuration)
	}
}

Prevention

When it happens

Trigger: StartLocalExecutionRequest.TotalDuration > 2147483647 or negative: unit confusion (passing nanoseconds instead of seconds), an unset field defaulted to -1, or summation overflow when totaling scenario durations.

Common situations: Callers summing scenario durations in the wrong unit; using -1 as 'not computed' marker; refactors changing the field's unit contract.

Related errors


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

Appendix: source

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

	// 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()
	}

	res, hr, err := c.apiClient.ProvisioningAPI.
		StartLocalExecutionTest(c.authCtx(ctx), loadTestID).
		K6IdempotencyKey(hex.EncodeToString(key[:])).
		StartLocalExecutionTestRequest(sdkReq).

View on GitHub (pinned to 01ffac6f24)