{"record":{"id":"35c21e32936ba922","repo":"grafana/k6","slug":"aggregation-period-is-not-allowed-to-have-sub-seco","errorCode":null,"errorMessage":"aggregation period is not allowed to have sub-second precision","messagePattern":"aggregation period is not allowed to have sub-second precision","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"output/cloud/expv2/collect.go","lineNumber":70,"sourceCode":"\tnowFunc func() time.Time\n\n\taggregationPeriod time.Duration\n\twaitPeriod        time.Duration\n\n\t// we should no longer have to handle metrics that have times long in the past. So instead of a\n\t// map, we can probably use a simple slice (or even an array!) as a ring buffer to store the\n\t// aggregation buckets. This should save us a some time, since it would make the lookups and WaitPeriod\n\t// checks basically O(1). And even if for some reason there are occasional metrics with past times that\n\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}","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/output/cloud/expv2/collect.go#L52-L88","documentation":"Returned by newCollector (output/cloud/expv2/collect.go:69-71) when the aggregation period is not a whole number of seconds (aggrPeriod != aggrPeriod.Truncate(time.Second)). Bucket boundaries are computed in whole seconds — bucketID is UnixNano/period and the flushed MetricSet reports aggregation_period in seconds as a uint32 (flush.go:183) — so sub-second precision (e.g. 500ms) cannot be represented faithfully and is rejected.","triggerScenarios":"K6_CLOUD_AGGREGATION_PERIOD=500ms (or 1500ms, 1.5s), or constructing the expv2 output config with AggregationPeriod: types.NullDurationFrom(500*time.Millisecond). Output.Start fails with 'failed to initialize the samples collector: aggregation period is not allowed to have sub-second precision'.","commonSituations":"Tuning aggregation latency down below 1s to make the Cloud dashboard update faster; values written as milliseconds by config tooling.","solutions":["Round the period to whole seconds; the minimum valid value is 1s","For near-real-time dashboards use 1s and accept the Cloud ingestion cadence, rather than fractional seconds"],"exampleFix":"# before\nK6_CLOUD_AGGREGATION_PERIOD=500ms k6 run -o cloud script.js\n\n# after\nK6_CLOUD_AGGREGATION_PERIOD=1s k6 run -o cloud script.js","handlingStrategy":"validation","validationCode":"# shell: require whole seconds\nP=\"${K6_CLOUD_AGGREGATION_PERIOD:-10s}\"\ncase \"$P\" in *ms | *us | *ns | *.*) echo \"aggregation period must be whole seconds\"; exit 1;; esac\nexport K6_CLOUD_AGGREGATION_PERIOD=\"$P\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Both cloud aggregation knobs only accept whole-second multiples","If a lower-latency pipeline is needed, use 1s rather than fractional values"],"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"}