grafana/k6 · error

token is required to create cloud API client

Error message

token is required to create cloud API client

What it means

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.

Source

Thrown at internal/cloudapi/v6/client.go:31

	"github.com/sirupsen/logrus"
	"go.k6.io/k6/v2/internal/cloudapi/clientcfg"
	"go.k6.io/k6/v2/internal/cloudapi/httperr"
)

// Client handles communication with the k6 Cloud API.
type Client struct {
	apiClient *k6cloud.APIClient
	token     string
	stackID   int32
	baseURL   string

	logger logrus.FieldLogger
}

// NewClient return a new client for the cloud API
func NewClient(logger logrus.FieldLogger, token, host, version string, timeout time.Duration) (*Client, error) {
	if token == "" {
		return nil, fmt.Errorf("token is required to create cloud API client")
	}

	cfg := clientcfg.New(host, version, "Global k6 Cloud API.", timeout)

	c := &Client{
		apiClient: k6cloud.NewAPIClient(cfg),
		token:     token,
		baseURL:   fmt.Sprintf("%s/cloud/v6", host),
		logger:    logger,
	}
	return c, nil
}

// SetStackID sets the stack ID for the client. It returns an error if
// stackID does not fit in the int32 range the underlying SDK requires for
// the X-Stack-Id header.
func (c *Client) SetStackID(stackID int64) error {
	if stackID < math.MinInt32 || stackID > math.MaxInt32 {

View on GitHub (pinned to 93accf6570)

Solutions

  1. Run `k6 cloud login` to store a token locally, or export K6_CLOUD_TOKEN
  2. If the cloud output is not intended, remove/disable it rather than running half-configured
  3. In Go code, resolve the token early and fail with your own message pointing at the config source
  4. Verify the variable is exported and non-empty in the actual shell/runner context

Example fix

# before
k6 run -o cloud script.js  # no token configured

# after
k6 cloud login  # or: export K6_CLOUD_TOKEN=<token>
k6 run -o cloud script.js
Defensive patterns

Strategy: validation

Validate before calling

token := os.Getenv("K6_CLOUD_TOKEN")
if strings.TrimSpace(token) == "" {
	return errors.New("no cloud token: run `k6 cloud login` or set K6_CLOUD_TOKEN")
}
client, err := v6.NewClient(logger, token, host, version, timeout)

Type guard

func hasCloudToken(token string) bool { return strings.TrimSpace(token) != "" }

Try / catch

client, err := v6.NewClient(logger, token, host, version, timeout)
if err != nil {
	if strings.Contains(err.Error(), "token is required") {
		// authentication was never configured; point the user at login/env setup
	}
	return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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