grafana/k6 · error
format of value must be k=v, received
Error message
format of value must be k=v, received %q
What it means
Returned while parsing K6_BROWSER_SCREENSHOTS_OUTPUT when a comma-separated segment does not contain exactly one '=' (the code splits each segment on '=' and requires exactly 2 parts). It fires for empty segments (trailing comma), segments with no '=', and — importantly — values that themselves contain '=' such as presigned URLs with query strings or base64 padding, because splitting then yields 3+ parts.
Solutions
- Remove stray segments/commas so every part is exactly key=value
- Keep '=' out of values: strip the query string from the url= value and pass authentication via header.<name>=<value> entries instead
- If the presigned URL cannot avoid '=', the parser cannot represent it — request a signature without '=' padding or upload to a URL without query params
Example fix
# before — presigned URL with '=' in the signature export K6_BROWSER_SCREENSHOTS_OUTPUT='url=https://s3.example.com/b?sig=abcd==' # after — bare URL, auth moved to a header export K6_BROWSER_SCREENSHOTS_OUTPUT='url=https://s3.example.com/b,header.X-Auth=abcd'
Defensive patterns
Strategy: validation
Validate before calling
const v = process.env.K6_BROWSER_SCREENSHOTS_OUTPUT ?? '';
if (v) {
const bad = v.split(',').filter(p => p.split('=').length !== 2);
if (bad.length) {
throw new Error(`segments without exactly one '=': ${bad.join(' | ')} — remove '=' inside values (e.g. presigned query strings)`);
}
} Prevention
- Never paste presigned URLs with query strings into the env var — move auth into header entries
- Strip base64 '=' padding from signatures or obtain padding-free signatures
- Watch for trailing commas that create empty segments
When it happens
Trigger: A trailing comma ('url=https://h/,'); a bare token ('basePath'); a URL with a query string ('url=https://h/?sig=abc'); an AWS/GCS presigned URL whose signature contains '=' padding; a doubled equals ('url==https://h/').
Common situations: Pasting a presigned S3/GCS upload URL straight into the env var — its X-Amz-Signature/goog-signature query parameters almost always contain '='. Also stray commas or missing '=' from hand-edited CI variables.
Related errors
- empty header key, received
- format of header must be header.k=v, received
- invalid option
- invalid url
- parsing
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/2fda3f96838f9ca9.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/browser/file_persister.go:52
}
// parsePresignedURLEnvVar will parse a value such as:
// url=https://127.0.0.1/,basePath=/screenshots,header.1=a,header.2=b
// and return them.
//
func parsePresignedURLEnvVar(envVarValue string) (presignedURLConfig, error) {
ss := strings.Split(envVarValue, ",")
presignedURL := presignedURLConfig{
headers: make(map[string]string),
}
for _, s := range ss {
// The key value pair should be of the form key=value, so split
// on '=' to retrieve the key and value separately.
kv := strings.Split(s, "=")
if len(kv) != 2 {
return presignedURLConfig{}, fmt.Errorf("format of value must be k=v, received %q", s)
}
k := kv[0]
v := kv[1]
// A key with "header." means that the header name is encoded in the
// key, separated by a ".". Split the header on "." to retrieve the
// header name. The header value should be present in v from the previous
// split.
var hv, hk string
if strings.Contains(k, "header.") {
hv = v
hh := strings.Split(k, ".")
if len(hh) != 2 {
return presignedURLConfig{}, fmt.Errorf("format of header must be header.k=v, received %q", s)
}
View on GitHub (pinned to 01ffac6f24)