{"record":{"id":"9171706a4a47fe6d","repo":"grafana/k6","slug":"invalid-tls-cacerts-value-v-it-needs-to-be-a","errorCode":null,"errorMessage":"invalid tls cacerts value: '%#v', it needs to be a string or an array of PEM formatted strings","messagePattern":"invalid tls cacerts value: '%#v', it needs to be a string or an array of PEM formatted strings","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/grpc/params.go","lineNumber":248,"sourceCode":"\t\t\treturn fmt.Errorf(\"invalid tls cert value: '%#v', it needs to be a PEM formatted string\", v)\n\t\t}\n\t}\n\tif key, keyok := params.TLS[\"key\"]; keyok {\n\t\tif _, ok = key.(string); !ok {\n\t\t\treturn fmt.Errorf(\"invalid tls key value: '%#v', it needs to be a PEM formatted string\", v)\n\t\t}\n\t}\n\tif pass, passok := params.TLS[\"password\"]; passok {\n\t\tif _, ok = pass.(string); !ok {\n\t\t\treturn fmt.Errorf(\"invalid tls password value: '%#v', it needs to be a string\", v)\n\t\t}\n\t}\n\tif cacerts, cacertsok := params.TLS[\"cacerts\"]; cacertsok {\n\t\tvar cacertsArray []any\n\t\tif cacertsArray, ok = cacerts.([]any); ok {\n\t\t\tfor _, cacertsArrayEntry := range cacertsArray {\n\t\t\t\tif _, ok = cacertsArrayEntry.(string); !ok {\n\t\t\t\t\treturn fmt.Errorf(\"invalid tls cacerts value: '%#v',\"+\n\t\t\t\t\t\t\" it needs to be a string or an array of PEM formatted strings\", v)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if _, ok = cacerts.(string); !ok {\n\t\t\treturn fmt.Errorf(\"invalid tls cacerts value: '%#v',\"+\n\t\t\t\t\" it needs to be a string or an array of PEM formatted strings\", v)\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":230,"sourceCodeEnd":259,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/grpc/params.go#L230-L259","documentation":"Thrown by k6's gRPC Client.connect() when tls.cacerts is an array but one of its entries is not a string. parseConnectTLSParam (internal/js/modules/k6/grpc/params.go:243-251) accepts cacerts either as a single PEM string or as an array; when it is an array, every element must itself be a PEM string. The message prints the whole tls map (v), not the offending entry.","triggerScenarios":"tls: { cacerts: ['-----BEGIN...', 42] }, cacerts: [['pem1', 'pem2']] (nested array), or an array containing null/objects. Mixing a string and a non-string in the array still fails because the loop checks each entry.","commonSituations":"Building the cacerts array dynamically (e.g. .filter() forgotten, a failed file read returning undefined pushed into the array); concatenating arrays where one element is a parsed certificate object.","solutions":["Ensure every element of the cacerts array is a PEM string: cacerts.filter((c) => typeof c === 'string').","Flatten nested arrays before passing: cacerts.flat().","For a single CA, the plain string form cacerts: pem is also accepted."],"exampleFix":"// before\nconst cas = ['-----BEGIN...', undefined];\nclient.connect('host:443', { tls: { cacerts: cas } });\n\n// after\nconst cas = ['-----BEGIN...', '-----BEGIN...'].filter((c) => typeof c === 'string');\nclient.connect('host:443', { tls: { cacerts: cas } });","handlingStrategy":"validation","validationCode":"function normalizeCacerts(cacerts) {\n  const arr = Array.isArray(cacerts) ? cacerts.flat() : [cacerts];\n  const pems = arr.filter((c) => typeof c === 'string' && c.includes('-----BEGIN'));\n  if (pems.length !== arr.length) throw new Error('cacerts entries must all be PEM strings');\n  return Array.isArray(cacerts) ? pems : pems[0];\n}","typeGuard":"const isCacerts = (v) => typeof v === 'string' || (Array.isArray(v) && v.every((c) => typeof c === 'string'));","tryCatchPattern":null,"preventionTips":["Build cacerts arrays with .filter((c) => typeof c === 'string') to drop failed reads.","Flatten nested arrays before passing them."],"tags":["grpc","tls","validation","cacerts"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}