{"record":{"id":"2fda3f96838f9ca9","repo":"grafana/k6","slug":"format-of-value-must-be-k-v-received-q","errorCode":null,"errorMessage":"format of value must be k=v, received %q","messagePattern":"format of value must be k=v, received %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/file_persister.go","lineNumber":52,"sourceCode":"}\n\n// parsePresignedURLEnvVar will parse a value such as:\n// url=https://127.0.0.1/,basePath=/screenshots,header.1=a,header.2=b\n// and return them.\n//\n\nfunc parsePresignedURLEnvVar(envVarValue string) (presignedURLConfig, error) {\n\tss := strings.Split(envVarValue, \",\")\n\n\tpresignedURL := presignedURLConfig{\n\t\theaders: make(map[string]string),\n\t}\n\tfor _, s := range ss {\n\t\t// The key value pair should be of the form key=value, so split\n\t\t// on '=' to retrieve the key and value separately.\n\t\tkv := strings.Split(s, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"format of value must be k=v, received %q\", s)\n\t\t}\n\n\t\tk := kv[0]\n\t\tv := kv[1]\n\n\t\t// A key with \"header.\" means that the header name is encoded in the\n\t\t// key, separated by a \".\". Split the header on \".\" to retrieve the\n\t\t// header name. The header value should be present in v from the previous\n\t\t// split.\n\t\tvar hv, hk string\n\t\tif strings.Contains(k, \"header.\") {\n\t\t\thv = v\n\n\t\t\thh := strings.Split(k, \".\")\n\t\t\tif len(hh) != 2 {\n\t\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"format of header must be header.k=v, received %q\", s)\n\t\t\t}\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/js/modules/k6/browser/browser/file_persister.go#L34-L70","documentation":"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.","triggerScenarios":"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/').","commonSituations":"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.","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"],"exampleFix":"# before — presigned URL with '=' in the signature\nexport K6_BROWSER_SCREENSHOTS_OUTPUT='url=https://s3.example.com/b?sig=abcd=='\n# after — bare URL, auth moved to a header\nexport K6_BROWSER_SCREENSHOTS_OUTPUT='url=https://s3.example.com/b,header.X-Auth=abcd'","handlingStrategy":"validation","validationCode":"const v = process.env.K6_BROWSER_SCREENSHOTS_OUTPUT ?? '';\nif (v) {\n  const bad = v.split(',').filter(p => p.split('=').length !== 2);\n  if (bad.length) {\n    throw new Error(`segments without exactly one '=': ${bad.join(' | ')} — remove '=' inside values (e.g. presigned query strings)`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["k6","browser","screenshots","environment-variable","presigned-url"],"backgroundTag":"invalid-env-var-format","analyzedSha":"01ffac6f245854c1b8adc6a69857c76a15f90022","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}