grafana/k6 · error
both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN…
Error message
both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN must be set together
What it means
When a cloud testRunID is already known (K6_CLOUD_PUSH_REF_ID / config PushRefID set), the output pushes metrics directly to an externally provisioned run instead of creating one. That mode requires both the push URL and the run-scoped token; having exactly one of K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN is a misconfiguration and is rejected as a defensive backstop.
Solutions
- Set both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN together, or set neither
- If k6 should provision the run itself, remove the PushRefID/ref and both scoped push credentials, and authenticate with the normal cloud token (K6_CLOUD_TOKEN)
- Audit the provisioning service/env files for the missing half of the pair
Example fix
# before export K6_CLOUD_TEST_RUN_TOKEN=abc123 # URL missing k6 run -o cloud script.js # after export K6_CLOUD_METRICS_PUSH_URL=https://ingress.grafana.net/... export K6_CLOUD_TEST_RUN_TOKEN=abc123 k6 run -o cloud script.js
Defensive patterns
Strategy: validation
Validate before calling
// Shell: enforce both-or-neither before running
if [ -n "${K6_CLOUD_METRICS_PUSH_URL:-}" ] || [ -n "${K6_CLOUD_TEST_RUN_TOKEN:-}" ]; then
: "${K6_CLOUD_METRICS_PUSH_URL:?must be set together with K6_CLOUD_TEST_RUN_TOKEN}"
: "${K6_CLOUD_TEST_RUN_TOKEN:?must be set together with K6_CLOUD_METRICS_PUSH_URL}"
fi
k6 run -o cloud script.js Type guard
function pushCredsPaired(env) {
return (env.K6_CLOUD_METRICS_PUSH_URL != null) === (env.K6_CLOUD_TEST_RUN_TOKEN != null);
} Prevention
- Treat K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN as an atomic pair in templates
- Validate secret-injection jobs for the complete set of push credentials
- Keep a lint rule in CI that greps for half-configured K6_CLOUD_* push variables
When it happens
Trigger: An external provisioning service injects only K6_CLOUD_TEST_RUN_TOKEN (or only K6_CLOUD_METRICS_PUSH_URL) together with a PushRefID; a hand-written cloud config or env file that sets one of the pair but not the other.
Common situations: Partial secrets injection in CI (token vault populated, URL variable missed); hand-rolled provisioning wrappers that copy config between systems and drop one key.
Related errors
- access token not configured
- both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN…
- failed to initialize cloud secret source
- influxdb's ConcurrentWrites must be a positive number
- missing required url
AI-assisted analysis of grafana/k6@8d06114777 (2026-08-18).
Data as JSON: /api/errors/a52aa37d7c5a509c.
Report an issue: GitHub.
Appendix: source
Thrown at internal/output/cloud/output.go:243
return nil
}
// Start calls the k6 Cloud API to initialize the test run, and then starts the
// goroutine that would listen for metric samples and send them to the cloud.
func (out *Output) Start() error {
if out.config.PushRefID.Valid {
out.testRunID = out.config.PushRefID.String
}
if out.testRunID != "" {
out.logger.WithField("testRunId", out.testRunID).Debug("Directly pushing metrics without init")
// Exactly one of the scoped push creds set is a misconfiguration.
// The cmd layer already validates this for the externally-provisioned
// env case (internal/cmd/outputs_cloud.go); this is the defensive
// backstop for any other source (e.g. a hand-written cloud config).
if out.config.MetricsPushURL.Valid != out.config.TestRunToken.Valid {
return errors.New(
"both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN " +
"must be set together")
}
// Provisioning-mode push. Armed whenever the scoped push credentials
// are present: either k6 self-provisioned (no PushRefID) or an external
// service provisioned the run and its creds were injected into the
// cloud config by the cmd layer (PushRefID set; that service owns
// create/start/notify).
if out.config.MetricsPushURL.Valid && out.config.TestRunToken.Valid {
if err := out.lazyInitProvisioning(); err != nil {
return err
}
}
return out.startVersionedOutput()
}
View on GitHub (pinned to 8d06114777)