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
- Verify the caller computes TotalDuration as the max scenario end time in seconds (e.g. via lib.Options.Scenarios getDurations), not nanoseconds.
- Replace -1/zero sentinels with the real computed duration before building the request.
- 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
- Compute TotalDuration in seconds from scenario end-times, never from time.Duration nanoseconds directly.
- Add unit-suffixed names (totalDurationSeconds) at construction sites to prevent unit mix-ups.
- Assert a sane upper bound (< 1 year) before any cloud call.
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)