{"record":{"id":"2de4db0707ec2161","repo":"grafana/k6","slug":"total-duration-w","errorCode":null,"errorMessage":"total_duration: %w","messagePattern":"total_duration: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloudapi/provisioning/api.go","lineNumber":210,"sourceCode":"\t// Generate idempotency key: 8 random bytes hex-encoded (16 chars).\n\tvar key [8]byte\n\tif _, err := rand.Read(key[:]); err != nil {\n\t\treturn nil, fmt.Errorf(\"generating idempotency key: %w\", err)\n\t}\n\n\t// SDK adapter: unmarshal json.RawMessage → map[string]any.\n\tvar opts map[string]any\n\tif err := json.Unmarshal(req.Options, &opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshalling options for SDK: %w\", err)\n\t}\n\n\tmaxVUs, err := toInt32(req.MaxVUs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"max_vus: %w\", err)\n\t}\n\ttotalDuration, err := toInt32(req.TotalDuration)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"total_duration: %w\", err)\n\t}\n\n\tsdkReq := k6cloud.NewStartLocalExecutionTestRequest(opts, maxVUs, totalDuration)\n\n\tif req.ArchiveSize > 0 {\n\t\tv, err := toInt32(req.ArchiveSize)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"archive_size: %w\", err)\n\t\t}\n\t\tsdkReq.SetArchiveSize(v)\n\t} else {\n\t\tsdkReq.SetArchiveSizeNil()\n\t}\n\n\tres, hr, err := c.apiClient.ProvisioningAPI.\n\t\tStartLocalExecutionTest(c.authCtx(ctx), loadTestID).\n\t\tK6IdempotencyKey(hex.EncodeToString(key[:])).\n\t\tStartLocalExecutionTestRequest(sdkReq).","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/cloudapi/provisioning/api.go#L192-L228","documentation":"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.","triggerScenarios":"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.","commonSituations":"Callers summing scenario durations in the wrong unit; using -1 as 'not computed' marker; refactors changing the field's unit contract.","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."],"exampleFix":"// before\nresp, err := c.StartLocalExecution(ctx, id, provisioning.StartLocalExecutionRequest{TotalDuration: totalDur})\n\n// after — assert sane seconds range before the call\nconst maxReasonableSeconds = 31536000 // 1 year\nif req.TotalDuration <= 0 || req.TotalDuration > maxReasonableSeconds {\n\treturn fmt.Errorf(\"total_duration %ds out of range (1..%d)\", req.TotalDuration, maxReasonableSeconds)\n}\nresp, err := c.StartLocalExecution(ctx, id, provisioning.StartLocalExecutionRequest{TotalDuration: totalDur})","handlingStrategy":"validation","validationCode":"const maxReasonableDurationSeconds = int64(31536000) // one year\n\nfunc validTotalDuration(v int64) bool {\n\treturn v > 0 && v <= maxReasonableDurationSeconds\n}\n\nif !validTotalDuration(req.TotalDuration) {\n\treturn fmt.Errorf(\"total_duration %ds outside supported range\", req.TotalDuration)\n}","typeGuard":null,"tryCatchPattern":"if _, err := c.StartLocalExecution(ctx, id, req); err != nil {\n\tif strings.Contains(err.Error(), \"total_duration\") && strings.Contains(err.Error(), \"overflows int32\") {\n\t\t// almost certainly a unit bug (ns vs s) — fix the computation, do not retry\n\t\treturn fmt.Errorf(\"total_duration=%ds implausible; verify scenario duration summation units\", req.TotalDuration)\n\t}\n}","preventionTips":["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."],"tags":["k6","cloud","provisioning","integer-overflow","validation","duration"],"backgroundTag":"integer-overflow","analyzedSha":"01ffac6f245854c1b8adc6a69857c76a15f90022","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}