{"record":{"id":"a52aa37d7c5a509c","repo":"grafana/k6","slug":"both-k6-cloud-metrics-push-url-and-k6-cloud-test-r-a52aa3","errorCode":null,"errorMessage":"both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN must be set together","messagePattern":"both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN must be set together","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/output/cloud/output.go","lineNumber":243,"sourceCode":"\treturn nil\n}\n\n// Start calls the k6 Cloud API to initialize the test run, and then starts the\n// goroutine that would listen for metric samples and send them to the cloud.\nfunc (out *Output) Start() error {\n\tif out.config.PushRefID.Valid {\n\t\tout.testRunID = out.config.PushRefID.String\n\t}\n\n\tif out.testRunID != \"\" {\n\t\tout.logger.WithField(\"testRunId\", out.testRunID).Debug(\"Directly pushing metrics without init\")\n\n\t\t// Exactly one of the scoped push creds set is a misconfiguration.\n\t\t// The cmd layer already validates this for the externally-provisioned\n\t\t// env case (internal/cmd/outputs_cloud.go); this is the defensive\n\t\t// backstop for any other source (e.g. a hand-written cloud config).\n\t\tif out.config.MetricsPushURL.Valid != out.config.TestRunToken.Valid {\n\t\t\treturn errors.New(\n\t\t\t\t\"both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN \" +\n\t\t\t\t\t\"must be set together\")\n\t\t}\n\n\t\t// Provisioning-mode push. Armed whenever the scoped push credentials\n\t\t// are present: either k6 self-provisioned (no PushRefID) or an external\n\t\t// service provisioned the run and its creds were injected into the\n\t\t// cloud config by the cmd layer (PushRefID set; that service owns\n\t\t// create/start/notify).\n\t\tif out.config.MetricsPushURL.Valid && out.config.TestRunToken.Valid {\n\t\t\tif err := out.lazyInitProvisioning(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn out.startVersionedOutput()\n\t}\n","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/grafana/k6/blob/8d06114777191d21ef885d05c5f8aa9e1ed838ae/internal/output/cloud/output.go#L225-L261","documentation":"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.","triggerScenarios":"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.","commonSituations":"Partial secrets injection in CI (token vault populated, URL variable missed); hand-rolled provisioning wrappers that copy config between systems and drop one key.","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"],"exampleFix":"# before\nexport K6_CLOUD_TEST_RUN_TOKEN=abc123   # URL missing\nk6 run -o cloud script.js\n# after\nexport K6_CLOUD_METRICS_PUSH_URL=https://ingress.grafana.net/...\nexport K6_CLOUD_TEST_RUN_TOKEN=abc123\nk6 run -o cloud script.js","handlingStrategy":"validation","validationCode":"// Shell: enforce both-or-neither before running\nif [ -n \"${K6_CLOUD_METRICS_PUSH_URL:-}\" ] || [ -n \"${K6_CLOUD_TEST_RUN_TOKEN:-}\" ]; then\n  : \"${K6_CLOUD_METRICS_PUSH_URL:?must be set together with K6_CLOUD_TEST_RUN_TOKEN}\"\n  : \"${K6_CLOUD_TEST_RUN_TOKEN:?must be set together with K6_CLOUD_METRICS_PUSH_URL}\"\nfi\nk6 run -o cloud script.js","typeGuard":"function pushCredsPaired(env) {\n  return (env.K6_CLOUD_METRICS_PUSH_URL != null) === (env.K6_CLOUD_TEST_RUN_TOKEN != null);\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["cloud","environment-variables","configuration","k6"],"backgroundTag":"incomplete-env-var-pair","analyzedSha":"8d06114777191d21ef885d05c5f8aa9e1ed838ae","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}