grafana/k6 · error

notify test run completed

Error message

notify test run completed: %w

What it means

Raised by provisioning.Client.NotifyTestRunCompleted after POST /provisioning/v1/test_runs/{id}/notify returned a non-2xx HTTP status. The provisioning package's CheckResponse(hr) inspects the response, so this error means the cloud API received the request but rejected it — the wrapped value is usually a ResponseError carrying status code and body. The notify call uses the scoped test-run token (injected via context), not the long-lived API token, so auth failures here implicate that scoped token, not your login token.

Solutions

  1. Verify testRunID and testRunToken come from the same StartLocalExecution response and were not reused from an earlier run
  2. Inspect the wrapped ResponseError body for the exact API reason (status code + message) before changing anything
  3. If 401/403, re-provision to obtain a fresh scoped token; do not substitute the global K6_CLOUD_TOKEN
  4. If 5xx persisted through SDK retries, retry NotifyTestRunCompleted after a short delay once the service recovers

Example fix

// before
_ = client.NotifyTestRunCompleted(ctx, staleRunID, staleToken, testErr)

// after
if err := client.NotifyTestRunCompleted(ctx, result.TestRunID, result.RuntimeConfig.Token, testErr); err != nil {
    var respErr *cloudapi.ResponseError
    if errors.As(err, &respErr) {
        logger.Errorf("notify rejected: status=%d body=%s", respErr.Response.StatusCode, respErr.Error())
    }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

// ensure the run + token pair is fresh before notifying
if result == nil || result.TestRunID == 0 {
    return fmt.Errorf("cannot notify: no provisioned test run")
}

Type guard

func isHTTPResponseError(err error) bool {
    var re *cloudapiv6.ResponseError
    return errors.As(err, &re)
}

Try / catch

if err := client.NotifyTestRunCompleted(ctx, runID, token, testErr); err != nil {
    var respErr *cloudapiv6.ResponseError
    if errors.As(err, &respErr) && respErr.Response != nil && respErr.Response.StatusCode >= 500 {
        time.Sleep(5 * time.Second) // SDK already retried 5xx; back off further
        err = client.NotifyTestRunCompleted(ctx, runID, token, testErr)
    }
    if err != nil { logger.WithError(err).Warn("cloud notify failed; run may show as unfinished") }
}

Prevention

When it happens

Trigger: Calling NotifyTestRunCompleted with an expired or wrong testRunToken (401/403), a testRunID that was never provisioned or already closed (404), a malformed notification model (400), or a 4xx from the provisioning API. 5xx is retried by the SDK, so surfacing here means retries were exhausted or the status was 4xx.

Common situations: Local-execution flow where the run took longer than the token/URL validity, re-using a testRunID from a previous run after the cloud run was deleted, clock skew, or a proxy stripping the Authorization header.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of grafana/k6@8d06114777 (2026-08-18). Data as JSON: /api/errors/036b52e513d0dbb7. Report an issue: GitHub.

Appendix: source

Thrown at internal/cloudapi/provisioning/notify.go:77

	// Authorization: Bearer <token>.
	scopedCtx := context.WithValue(ctx, k6cloud.ContextAccessToken, testRunToken)

	model := k6cloud.NewScriptExecutionCompletedNotificationApiModel("script_execution_completed")
	if ne := mapTestErrorToNotifyCode(testErr); ne != nil {
		model.SetError(*k6cloud.NewScriptExecutionError(ne.Code, ne.Reason))
	} else {
		model.SetErrorNil()
	}

	hr, err := c.apiClient.ProvisioningAPI.
		TestRunsNotify(scopedCtx, testRunID).
		ScriptExecutionCompletedNotificationApiModel(model).
		Execute()
	defer closeResponse(hr, &err)

	if hr != nil {
		if respErr := CheckResponse(hr); respErr != nil {
			return fmt.Errorf("notify test run completed: %w", respErr)
		}
	}
	if err != nil {
		return fmt.Errorf("notify test run completed: %w", err)
	}

	return nil
}

View on GitHub (pinned to 8d06114777)