{"record":{"id":"272a090281680cf9","repo":"grafana/k6","slug":"k6-cloud-logs-push-url-requires-k6-cloud-test-run","errorCode":null,"errorMessage":"K6_CLOUD_LOGS_PUSH_URL requires K6_CLOUD_TEST_RUN_TOKEN","messagePattern":"K6_CLOUD_LOGS_PUSH_URL requires K6_CLOUD_TEST_RUN_TOKEN","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/outputs_cloud.go","lineNumber":231,"sourceCode":"func applyExternalProvisioningCreds(\n\tgs *state.GlobalState, test *loadedAndConfiguredTest, conf *cloudapi.Config,\n) error {\n\t// The log-push config is env-supplied for an external run and likewise not\n\t// env-bound on the Config, so read it explicitly here (before the checks\n\t// below, which require the token when a logs URL is set).\n\tif err := applyExternalLogsConfig(gs, conf); err != nil {\n\t\treturn err\n\t}\n\tpushURL := gs.Env[\"K6_CLOUD_METRICS_PUSH_URL\"]\n\ttoken := gs.Env[\"K6_CLOUD_TEST_RUN_TOKEN\"]\n\tif (pushURL == \"\") != (token == \"\") {\n\t\treturn errors.New(\"both K6_CLOUD_METRICS_PUSH_URL and \" +\n\t\t\t\"K6_CLOUD_TEST_RUN_TOKEN must be set together\")\n\t}\n\t// A logs push URL is authenticated with the same scoped token, so reject a\n\t// logs URL supplied without it rather than silently streaming nothing.\n\tif token == \"\" && conf.LogsPushURL.Valid && conf.LogsPushURL.String != \"\" {\n\t\treturn errors.New(\"K6_CLOUD_LOGS_PUSH_URL requires K6_CLOUD_TEST_RUN_TOKEN\")\n\t}\n\tif pushURL == \"\" {\n\t\treturn nil\n\t}\n\n\tconf.MetricsPushURL = null.StringFrom(pushURL)\n\tconf.TestRunToken = null.StringFrom(token)\n\traw, err := cloudConfToRawMessage(*conf)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not serialize cloud configuration: %w\", err)\n\t}\n\tif test.derivedConfig.Collectors == nil {\n\t\ttest.derivedConfig.Collectors = make(map[string]json.RawMessage)\n\t}\n\ttest.derivedConfig.Collectors[builtinOutputCloud.String()] = raw\n\treturn nil\n}\n","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/cmd/outputs_cloud.go#L213-L249","documentation":"Logs for a cloud run are pushed to K6_CLOUD_LOGS_PUSH_URL authenticated with the same scoped token as metrics. applyExternalProvisioningCreds rejects a logs URL supplied without K6_CLOUD_TEST_RUN_TOKEN rather than silently streaming nothing.","triggerScenarios":"Setting K6_CLOUD_LOGS_PUSH_URL (or a LogsPushURL in config) while K6_CLOUD_TEST_RUN_TOKEN is empty and no token is otherwise provisioned.","commonSituations":"Enabling cloud log shipping piecemeal in CI; a redacted/missing token with the logs URL left in place; per-stage env files where the token line was dropped.","solutions":["Set K6_CLOUD_TEST_RUN_TOKEN alongside K6_CLOUD_LOGS_PUSH_URL (and K6_CLOUD_METRICS_PUSH_URL)","If you do not want log shipping, unset K6_CLOUD_LOGS_PUSH_URL","Check that the token was not stripped by secret masking in CI"],"exampleFix":"# before\nexport K6_CLOUD_LOGS_PUSH_URL=https://.../logs\nk6 run --out cloud script.js\n\n# after\nexport K6_CLOUD_LOGS_PUSH_URL=https://.../logs\nexport K6_CLOUD_METRICS_PUSH_URL=https://.../api/v1/write\nexport K6_CLOUD_TEST_RUN_TOKEN=eyJ...\nk6 run --out cloud script.js","handlingStrategy":"validation","validationCode":"if [ -n \"$K6_CLOUD_LOGS_PUSH_URL\" ] && [ -z \"$K6_CLOUD_TEST_RUN_TOKEN\" ]; then\n  echo \"K6_CLOUD_LOGS_PUSH_URL requires K6_CLOUD_TEST_RUN_TOKEN\" >&2; exit 1;\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat the token as mandatory whenever any K6_CLOUD_*_PUSH_URL is present","Keep cloud log-push config in the same env file as the token so they move together","Audit CI env files after secret rotation — tokens expire, URLs linger"],"tags":["cloud","environment","configuration","auth","logging"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}