{"record":{"id":"fb94c163dad22762","repo":"grafana/k6","slug":"token-is-required-to-create-cloud-api-client","errorCode":null,"errorMessage":"token is required to create cloud API client","messagePattern":"token is required to create cloud API client","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cloudapi/v6/client.go","lineNumber":31,"sourceCode":"\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/v2/internal/cloudapi/clientcfg\"\n\t\"go.k6.io/k6/v2/internal/cloudapi/httperr\"\n)\n\n// Client handles communication with the k6 Cloud API.\ntype Client struct {\n\tapiClient *k6cloud.APIClient\n\ttoken     string\n\tstackID   int32\n\tbaseURL   string\n\n\tlogger logrus.FieldLogger\n}\n\n// NewClient return a new client for the cloud API\nfunc NewClient(logger logrus.FieldLogger, token, host, version string, timeout time.Duration) (*Client, error) {\n\tif token == \"\" {\n\t\treturn nil, fmt.Errorf(\"token is required to create cloud API client\")\n\t}\n\n\tcfg := clientcfg.New(host, version, \"Global k6 Cloud API.\", timeout)\n\n\tc := &Client{\n\t\tapiClient: k6cloud.NewAPIClient(cfg),\n\t\ttoken:     token,\n\t\tbaseURL:   fmt.Sprintf(\"%s/cloud/v6\", host),\n\t\tlogger:    logger,\n\t}\n\treturn c, nil\n}\n\n// SetStackID sets the stack ID for the client. It returns an error if\n// stackID does not fit in the int32 range the underlying SDK requires for\n// the X-Stack-Id header.\nfunc (c *Client) SetStackID(stackID int64) error {\n\tif stackID < math.MinInt32 || stackID > math.MaxInt32 {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/cloudapi/v6/client.go#L13-L49","documentation":"v6.NewClient (internal/cloudapi/v6/client.go:31) refuses to construct the cloud API client when the token is empty, since every request would otherwise fail with an unexplained 401. This guard fires before any network activity, making missing authentication obvious at construction time.","triggerScenarios":"Constructing the v6 client (directly or via provisioning.NewClient) with an empty token: cloud output configured without `k6 cloud login` and without K6_CLOUD_TOKEN; code reading the token from an unset variable.","commonSituations":"Fresh CI runners without the k6 Cloud config file; pipelines missing the token secret; scripts assuming a stored login that exists only on a developer's machine.","solutions":["Run `k6 cloud login` to store a token locally, or export K6_CLOUD_TOKEN","If the cloud output is not intended, remove/disable it rather than running half-configured","In Go code, resolve the token early and fail with your own message pointing at the config source","Verify the variable is exported and non-empty in the actual shell/runner context"],"exampleFix":"# before\nk6 run -o cloud script.js  # no token configured\n\n# after\nk6 cloud login  # or: export K6_CLOUD_TOKEN=<token>\nk6 run -o cloud script.js","handlingStrategy":"validation","validationCode":"token := os.Getenv(\"K6_CLOUD_TOKEN\")\nif strings.TrimSpace(token) == \"\" {\n\treturn errors.New(\"no cloud token: run `k6 cloud login` or set K6_CLOUD_TOKEN\")\n}\nclient, err := v6.NewClient(logger, token, host, version, timeout)","typeGuard":"func hasCloudToken(token string) bool { return strings.TrimSpace(token) != \"\" }","tryCatchPattern":"client, err := v6.NewClient(logger, token, host, version, timeout)\nif err != nil {\n\tif strings.Contains(err.Error(), \"token is required\") {\n\t\t// authentication was never configured; point the user at login/env setup\n\t}\n\treturn err\n}","preventionTips":["Check the token once at startup with a clear, actionable error","Export K6_CLOUD_TOKEN explicitly in CI and verify it in a preflight step","Don't configure the cloud output at all when no cloud run is intended"],"tags":["auth","token","configuration","client-construction"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}