grafana/k6 · error
a /v1 suffix is expected in the Cloud service's BaseURL path
Error message
a /v1 suffix is expected in the Cloud service's BaseURL path
What it means
Returned by deriveMetricsURL (output/cloud/expv2/metrics_client.go:41-43), which builds the v2 metrics-ingestion URL from the Cloud service base URL. The cloudapi.Client hard-codes /v1 for test lifecycle management, so the expv2 output requires the base URL to end in /v1 and derives ingestion as <trimmed>/v2/metrics/<testRunID> (line 47). A base URL without the /v1 suffix means the API-version convention was violated and URL derivation would be wrong. Reached from Output.Start (output.go:134) when neither metricsHTTPClient nor metricsURL was injected; the error surfaces wrapped as 'failed to derive the metrics push URL'.
Source
Thrown at output/cloud/expv2/metrics_client.go:42
// the collected metrics from the Cloud output
// to the remote service.
type metricsClient struct {
httpClient metricsHTTPClient
url string
}
// deriveMetricsURL builds the v2 metrics-ingestion URL from the Cloud
// service base URL, used when no explicit push URL was provided.
//
// The cloudapi.Client works across different versions of the API: test
// lifecycle management is under /v1 while metrics ingestion is /v2.
// The client has /v1 hard-coded, so we trim it and replace with /v2.
// A versioned client would be better but it would require a breaking
// change, and other services (e.g. k6-operator) depend on it, so we want
// to stabilize the API first.
func deriveMetricsURL(baseURL, testRunID string) (string, error) {
if !strings.HasSuffix(baseURL, "/v1") {
return "", errors.New("a /v1 suffix is expected in the Cloud service's BaseURL path")
}
if testRunID == "" {
return "", errors.New("TestRunID of the test is required")
}
return strings.TrimSuffix(baseURL, "/v1") + "/v2/metrics/" + testRunID, nil
}
// newMetricsClientWithURL builds a metricsClient with an explicit push URL.
// It is the single metricsClient constructor: callers that need the
// host-derived URL compute it via deriveMetricsURL first.
func newMetricsClientWithURL(c metricsHTTPClient, url string) (*metricsClient, error) {
if url == "" {
return nil, errors.New("metrics push URL is required")
}
return &metricsClient{
httpClient: c,
url: url,
}, nilView on GitHub (pinned to 93accf6570)
Solutions
- Append /v1 to the host, e.g. K6_CLOUD_HOST=https://cloudutils.grafana.com/v1
- If the endpoint genuinely has a different versioning scheme, bypass derivation by providing an explicit push URL: set both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN (output.go requires them together)
Example fix
# before K6_CLOUD_HOST=https://cloudutils.grafana.com k6 cloud script.js # after K6_CLOUD_HOST=https://cloudutils.grafana.com/v1 k6 cloud script.js
Defensive patterns
Strategy: validation
Validate before calling
# shell: assert the /v1 suffix before running
H="${K6_CLOUD_HOST:-https://cloudutils.grafana.com/v1}"
case "$H" in */v1) ;; *) echo "K6_CLOUD_HOST must end with /v1"; exit 1;; esac
export K6_CLOUD_HOST="$H" Prevention
- Always include the /v1 path in K6_CLOUD_HOST (e.g. https://cloudutils.grafana.com/v1, https://api.k6.io/v1)
- If your gateway cannot keep /v1, bypass derivation with K6_CLOUD_METRICS_PUSH_URL plus K6_CLOUD_TEST_RUN_TOKEN (they must be set together)
When it happens
Trigger: Setting K6_CLOUD_HOST=https://api.cloud.k6.io (no /v1), or a custom/proxy Cloud host like https://cloud.internal.example. Defaults such as https://cloudutils.grafana.com/v1 and https://api.k6.io/v1 already carry the suffix.
Common situations: Pointing k6 at Grafana Cloud or a self-hosted/proxied Cloud endpoint and forgetting the /v1 path; env var typos; on-prem gateway URLs rewritten to strip path prefixes.
Related errors
- aggregation period is not allowed to be zero
- aggregation wait period is not allowed to be zero
- TestRunID of the test is required
- tests with unspecified duration are not allowed when outputt
- both K6_CLOUD_METRICS_PUSH_URL and K6_CLOUD_TEST_RUN_TOKEN m
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/952960bd1d437ec5.
Report an issue: GitHub.