grafana/k6 · error
test run completed before k6 could start
Error message
test run completed before k6 could start
What it means
Returned by Client.WaitForTestRunReady (internal/cloudapi/provisioning/api.go:167) when the polled test run reports status 'completed' before k6 ever saw 'initializing'. The state machine moved to a terminal finished state while the local k6 process was still waiting for its cue to start executing, so there is nothing left to drive: the backend considers the run done. This usually indicates a state race or configuration degenerate enough that the backend finished (or thought it finished) instantly.
Solutions
- Open the test run page for the ID being polled and check its timeline and results — if it genuinely ran, your local invocation lost the race to another one.
- Audit the script's executor config: every scenario needs a non-zero duration/VUs so the run has actual work.
- Make sure each invocation generates a fresh run (the client already mints a new idempotency key per StartLocalExecution call) — never reuse a previous request.
- If the run shows no work at all in the UI yet reports completed, report it with the run ID to k6 Cloud support.
Defensive patterns
Strategy: try-catch
Validate before calling
// Before starting, assert the script actually schedules work.
func hasRunnableWork(opts lib.Options) bool {
for _, s := range opts.Scenarios {
if s == nil {
continue
}
if d := s.GetDuration(); d > 0 || s.GetVUs() > 0 {
return true
}
}
return false
} Try / catch
if err := c.WaitForTestRunReady(ctx, testRunID, poll); err != nil {
if strings.Contains(err.Error(), "completed before k6 could start") {
// inspect the run page: either a state race or a degenerate zero-work config
log.Warnf("run %d reported completed during wait; inspect its timeline", testRunID)
}
return err
} Prevention
- Validate every scenario has non-zero duration/VUs before invoking cloud provisioning.
- Never retry StartLocalExecution with a reused request; let the client mint a fresh idempotency key each time.
- Investigate duplicate/parallel invocations of the same load test definition in CI.
When it happens
Trigger: A test configuration the backend executes/finishes with zero local work (e.g. zero VUs or a zero/blank schedule slipping through); replaying a StartLocalExecution whose idempotency key collides with an already-completed run; backend state machine anomalies where 'completed' skips 'initializing'.
Common situations: Scripts with misconfigured executors producing empty schedules; retrying a start request after a network error where the first request actually succeeded and the run already finished; backend incidents flipping run states.
Related errors
- fetching test status
- test run aborted before starting
- test run aborted before starting
- archive_size
- archive upload failed
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/c377a312c1c28033.
Report an issue: GitHub.
Appendix: source
Thrown at internal/cloudapi/provisioning/api.go:167
switch v6.Status(status) {
case v6.StatusInitializing:
return nil
case v6.StatusAborted:
var abortMsg string
for _, e := range progress.StatusHistory {
if e.Status == v6.StatusAborted && e.Message != "" {
abortMsg = e.Message
break
}
}
if abortMsg != "" {
return fmt.Errorf("test run aborted before starting: %s", abortMsg)
}
return fmt.Errorf("test run aborted before starting")
case v6.StatusCompleted:
return fmt.Errorf("test run completed before k6 could start")
default:
// created, queued, or any unrecognised state — keep polling.
if status != lastStatus {
c.logger.WithField("status", progress.FormatStatus()).Debug("test status")
lastStatus = status
}
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(pollInterval):
// continue polling
}
}
}
View on GitHub (pinned to 01ffac6f24)