grafana/k6 · error
fetching test status
Error message
fetching test status: %w
What it means
Returned by Client.WaitForTestRunReady (internal/cloudapi/provisioning/api.go:144) when the underlying v6Client.FetchTest call fails while polling GET /cloud/v6/test_runs/{id}. A single failed poll aborts the whole wait — there is no retry around FetchTest at this layer — so even one transient failure (network blip, 401, 5xx) ends the wait-for-ready phase and the run stops before starting.
Solutions
- Inspect the wrapped error: 401/403 => token problem, 404 => test run gone, transport errors => network, context.Canceled => the run was interrupted locally.
- Re-run the test; if the queue wait is long and the network is flaky, that alone can trigger it.
- Verify the token still has access to the load test / project in the Grafana Cloud k6 UI.
- If you control the caller, wrap WaitForTestRunReady with a bounded retry loop so single-poll failures don't kill the run.
- Check status.k6.io / Grafana Cloud status page for API incidents during the wait window.
Example fix
// before
if err := c.WaitForTestRunReady(ctx, testRunID, pollInterval); err != nil { return err }
// after — tolerate transient poll failures without masking terminal ones
var err error
for attempt := 0; attempt < 3; attempt++ {
err = c.WaitForTestRunReady(ctx, testRunID, pollInterval)
if err == nil { break }
var apiErr *cloudapi.APIError // adapt to the v6 client's typed error
if errors.As(err, &apiErr) && (apiErr.Code == 404 || apiErr.Code == 401) {
break // terminal — retrying cannot help
}
time.Sleep(time.Duration(attempt+1) * 2 * time.Second)
}
if err != nil { return err } Defensive patterns
Strategy: retry
Try / catch
// Wrap the wait so a single failed poll doesn't kill a queued run.
err := c.WaitForTestRunReady(ctx, testRunID, poll)
if err != nil && !strings.Contains(err.Error(), "aborted before starting") &&
!strings.Contains(err.Error(), "completed before") && !errors.Is(err, context.Canceled) {
// transient poll failure — bounded backoff retry
for i := 1; i <= 2 && err != nil; i++ {
time.Sleep(time.Duration(i*3) * time.Second)
err = c.WaitForTestRunReady(ctx, testRunID, poll)
}
} Prevention
- Use a long-lived, permission-stable token when queue waits can be long.
- Keep network connectivity stable during the wait phase; avoid killing Wi-Fi/VPN mid-poll.
- Record the test run ID at start so a failed poll can be inspected in the UI afterwards.
When it happens
Trigger: Any FetchTest error inside the polling loop: expired/revoked API token mid-wait, test run deleted in the UI (404), network interruption, cloud API returning 4xx/5xx, or the parent context being cancelled (surfacing as ctx error inside the HTTP call).
Common situations: Long queue times on k6 Cloud with flaky connectivity; token permissions changed or token revoked while the test sat in queue; polling a test run someone deleted; strict egress firewalls dropping long-lived idle sessions.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- test run aborted before starting
- test run aborted before starting
- test run completed before k6 could start
- archive_size
- archive upload failed
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/26211ddb113868f4.
Report an issue: GitHub.
Appendix: source
Thrown at internal/cloudapi/provisioning/api.go:144
// WaitForTestRunReady polls GET /cloud/v6/test_runs/{id} until the
// backend status becomes "initializing" (signalling that k6 can begin
// local execution). Returns an error if the test run reaches "aborted"
// or "completed" first. Cancellable via context. Logs status transitions
// at Debug level once per change.
//
// If pollInterval is <= 0 the defaultWaitPollInterval is used.
func (c *Client) WaitForTestRunReady(ctx context.Context, testRunID int64, pollInterval time.Duration) error {
if pollInterval <= 0 {
pollInterval = defaultWaitPollInterval
}
var lastStatus string
for {
progress, err := c.v6Client.FetchTest(ctx, testRunID)
if err != nil {
return fmt.Errorf("fetching test status: %w", err)
}
status := progress.Status.String()
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)View on GitHub (pinned to 01ffac6f24)