grafana/k6 · error

both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN m

Error message

both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN must be set together

What it means

Thrown during cloud output Start() when the run is in direct-push mode (a testRunID exists, from K6_CLOUD_PUSH_REF_ID or a self-provisioned run) and exactly one of the scoped push credentials is set. The direct-push path requires K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN as a pair; the check is XOR-style (MetricsPushURL.Valid != TestRunToken.Valid) and acts as a defensive backstop behind the cmd-layer validation in internal/cmd/outputs_cloud.go.

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 93accf6570)

Solutions

  1. Set both variables together: K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN
  2. If you do not intend to push directly, unset BOTH variables so k6 falls back to normal cloud provisioning
  3. Search the environment and .env files for a stray K6_CLOUD_TEST_RUN_TOKEN or K6_CLOUD_METRICS_PUSH_URL: env | grep K6_CLOUD

Example fix

# before
export K6_CLOUD_TEST_RUN_TOKEN=abc123
# only token set -> error

# after (direct push)
export K6_CLOUD_METRICS_PUSH_URL=https://cloudapi.k6.io/api/v1/metrics/push
export K6_CLOUD_TEST_RUN_TOKEN=abc123

# after (normal provisioning)
unset K6_CLOUD_TEST_RUN_TOKEN K6_CLOUD_METRICS_PUSH_URL
Defensive patterns

Strategy: validation

Validate before calling

# Both or neither — check before running k6:
set -- $K6_CLOUD_METRICS_PUSH_URL $K6_CLOUD_TEST_RUN_TOKEN
if [ -n "$K6_CLOUD_METRICS_PUSH_URL" ] || [ -n "$K6_CLOUD_TEST_RUN_TOKEN" ]; then
  [ -n "$K6_CLOUD_METRICS_PUSH_URL" ] && [ -n "$K6_CLOUD_TEST_RUN_TOKEN" ] || { echo 'set both push URL and token, or neither'; exit 1; }
fi

Prevention

When it happens

Trigger: Hand-written cloud config where only one of metricsPushURL/testRunToken is present; exporting K6_CLOUD_TEST_RUN_TOKEN in the environment without K6_CLOUD_METRICS_PUSH_URL (or vice versa) while also having a push ref id (K6_CLOUD_PUSH_REF_ID) or otherwise entering the direct-push branch; a Go program constructing output.Params with a partial cloud config JSON.

Common situations: Scripts migrated from an older k6 that only needed a token; CI pipelines where the push URL variable was forgotten in one job template; shell profiles that set K6_CLOUD_TEST_RUN_TOKEN globally, surprising later runs; integrations that inject credentials one at a time.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/a52aa37d7c5a509c. Report an issue: GitHub.