{"record":{"id":"e32d478d0c916062","repo":"grafana/k6","slug":"aggregation-wait-period-is-not-allowed-to-have-sub","errorCode":null,"errorMessage":"aggregation wait period is not allowed to have sub-second precision","messagePattern":"aggregation wait period is not allowed to have sub-second precision","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"output/cloud/expv2/collect.go","lineNumber":79,"sourceCode":"\t// don't fit in the chosen ring buffer size, we could just send them along to the buffer unaggregated\n\ttimeBuckets map[int64]map[metrics.TimeSeries]metricValue\n}\n\nfunc newCollector(aggrPeriod, waitPeriod time.Duration) (*collector, error) {\n\tif aggrPeriod == 0 {\n\t\treturn nil, errors.New(\"aggregation period is not allowed to be zero\")\n\t}\n\tif aggrPeriod != aggrPeriod.Truncate(time.Second) {\n\t\treturn nil, errors.New(\"aggregation period is not allowed to have sub-second precision\")\n\t}\n\tif waitPeriod == 0 {\n\t\t// TODO: we could simplify the expiring logic\n\t\t// just having an internal static logic.\n\t\t// Like skip only not closed buckets bucketEnd > now.\n\t\treturn nil, errors.New(\"aggregation wait period is not allowed to be zero\")\n\t}\n\tif waitPeriod != waitPeriod.Truncate(time.Second) {\n\t\treturn nil, errors.New(\"aggregation wait period is not allowed to have sub-second precision\")\n\t}\n\treturn &collector{\n\t\tbq:                bucketQ{},\n\t\tnowFunc:           time.Now,\n\t\ttimeBuckets:       make(map[int64]map[metrics.TimeSeries]metricValue),\n\t\taggregationPeriod: aggrPeriod,\n\t\twaitPeriod:        waitPeriod,\n\t}, nil\n}\n\n// CollectSamples drain the buffer and collect all the samples.\nfunc (c *collector) CollectSamples(containers []metrics.SampleContainer) {\n\t// Distribute all newly buffered samples into related buckets\n\tfor _, sampleContainer := range containers {\n\t\tsamples := sampleContainer.GetSamples()\n\n\t\tfor i := range samples {\n\t\t\tc.collectSample(samples[i])","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/output/cloud/expv2/collect.go#L61-L97","documentation":"Returned by newCollector (output/cloud/expv2/collect.go:78-80) when the aggregation wait period has sub-second precision (waitPeriod != waitPeriod.Truncate(time.Second)). Like the aggregation period, the wait period participates in whole-second bucket arithmetic (collect.go:164 divides by the aggregation period after subtracting the wait), so fractional seconds such as 300ms are rejected.","triggerScenarios":"K6_CLOUD_AGGREGATION_WAIT_PERIOD=300ms or 1.5s, or programmatic config AggregationWaitPeriod: types.NullDurationFrom(300*time.Millisecond). Output.Start returns 'failed to initialize the samples collector: aggregation wait period is not allowed to have sub-second precision'.","commonSituations":"Fine-grained latency tuning of the Cloud output pipeline; values expressed in milliseconds by deployment tooling.","solutions":["Round the wait period to whole seconds; the minimum valid value is 1s"],"exampleFix":"# before\nK6_CLOUD_AGGREGATION_WAIT_PERIOD=300ms k6 run -o cloud script.js\n\n# after\nK6_CLOUD_AGGREGATION_WAIT_PERIOD=1s k6 run -o cloud script.js","handlingStrategy":"validation","validationCode":"# shell: require whole seconds for the wait period too\nW=\"${K6_CLOUD_AGGREGATION_WAIT_PERIOD:-5s}\"\ncase \"$W\" in *ms | *us | *ns | *.*) echo \"wait period must be whole seconds\"; exit 1;; esac\nexport K6_CLOUD_AGGREGATION_WAIT_PERIOD=\"$W\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Apply the same whole-second rule to wait and aggregation periods","Document the two knobs together in CI templates so they are always set as a pair"],"tags":["cloud-output","aggregation","config","duration"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}