grafana/k6 · error
total_duration: %w
Error message
total_duration: %w
What it means
Client.StartLocalExecution (internal/cloudapi/provisioning/api.go:210) converts req.TotalDuration (seconds, int64) to int32 for the cloud API schema. int32 max is ~2.1 billion seconds (~68 years), so a real duration never overflows; hitting this error means the value is wrong — typically a unit confusion (milliseconds or nanoseconds passed as seconds) or a garbage/negative sentinel.
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 93accf6570)
Solutions
- Verify the duration is expressed in seconds before building the request
- Range-check the computed total against a sane maximum (e.g. 30 days) and fail early with a clear message
- Re-run k6 inspect on the script to see the effective duration options
- Fix the upstream duration calculation rather than catching the error
Example fix
// before
req := provisioning.StartLocalExecutionRequest{
TotalDuration: totalDurationMs, // oops: milliseconds, not seconds
}
// after
totalSeconds := int64(totalDuration / time.Second)
if totalSeconds <= 0 || totalSeconds > 30*24*3600 {
return fmt.Errorf("implausible total duration: %ds", totalSeconds)
}
req := provisioning.StartLocalExecutionRequest{TotalDuration: totalSeconds} Defensive patterns
Strategy: validation
Validate before calling
totalSeconds := int64(total / time.Second)
if totalSeconds <= 0 || totalSeconds > 365*24*3600 {
return fmt.Errorf("total_duration %ds implausible; check units", totalSeconds)
} Type guard
func fitsInt32(v int64) bool { return v >= math.MinInt32 && v <= math.MaxInt32 } Try / catch
if err := client.StartLocalExecution(ctx, id, req); err != nil {
if strings.HasPrefix(err.Error(), "total_duration:") {
// suspect a unit mismatch (ms/ns passed as seconds) upstream
}
return err
} Prevention
- Convert durations with explicit time.Second division in exactly one place
- Sanity-check computed durations against a human-plausible maximum
- Unit-test the duration computation, not just the error path
When it happens
Trigger: TotalDuration computed by summing executor durations with the wrong unit, a duration value derived from an unchecked env/flag, or an overflowed negative number from caller arithmetic.
Common situations: Custom tooling that translates durations and drops a division by time.Second; options with enormous -d values from templating mistakes.
Related errors
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/2de4db0707ec2161.
Report an issue: GitHub.