{"record":{"id":"d97a47e0a160e92b","repo":"grafana/k6","slug":"format-of-header-must-be-header-k-v-received-q","errorCode":null,"errorMessage":"format of header must be header.k=v, received %q","messagePattern":"format of header must be header\\.k=v, received %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/file_persister.go","lineNumber":68,"sourceCode":"\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\n\t\t\tk = hh[0]\n\t\t\thk = hh[1]\n\n\t\t\tif hk == \"\" {\n\t\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"empty header key, received %q\", s)\n\t\t\t}\n\t\t}\n\n\t\tswitch k {\n\t\tcase \"url\":\n\t\t\tu, err := url.ParseRequestURI(v)\n\t\t\tif err != nil && u.Scheme != \"\" && u.Host != \"\" {\n\t\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"invalid url %q\", s)\n\t\t\t}\n\t\t\tpresignedURL.getterURL = v\n\t\tcase \"basePath\":","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/browser/file_persister.go#L50-L86","documentation":"A key containing the substring 'header.' does not split on '.' into exactly two parts (file_persister.go:68). Header entries must have the exact form header.<name>=<value>, so extra dots in the key are rejected.","triggerScenarios":"K6_BROWSER_SCREENSHOTS_OUTPUT contains 'header.Accept-Encoding=gzip' (dot inside the header name), 'x.header.a=1', or 'header.1.2=v' - the key contains 'header.' and splits into 3 parts instead of 2.","commonSituations":"Copying multi-part header names (Accept-Encoding, Content-Disposition) verbatim into the env var; assuming a numbered header list syntax like 'header.1.1='; key typos introduced by shell word-splitting.","solutions":["Use exactly one dot: header.Name=value; for header names containing dots, replace the dot with an underscore or the header name the server actually expects","Check for stray dots in the key portion of every header.* segment","Test the value with: echo \"$V\" | tr ',' '\\n' | grep 'header\\.' | awk -F. 'NF!=2{print \"bad header: \"$0; exit 1}'"],"exampleFix":"# before\nK6_BROWSER_SCREENSHOTS_OUTPUT=\"url=https://h/,header.Accept-Encoding=gzip\"\n# after\nK6_BROWSER_SCREENSHOTS_OUTPUT=\"url=https://h/,header.AcceptEncoding=gzip\"","handlingStrategy":"validation","validationCode":"const bad = v.split(',').filter(s => s.includes('header.') && s.split('=')[0].split('.').length !== 2);\nif (bad.length) throw new Error(`malformed header segments: ${bad.join(', ')}`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use exactly one dot in header keys (header.Name=value)","Avoid real header names containing dots, or substitute an underscore","Document the exact grammar next to the CI variable definition"],"tags":["k6","browser","environment-variable","parsing","http-headers"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}