{"record":{"id":"9cd0dd5c5b42869f","repo":"grafana/k6","slug":"invalid-tls-cert-value-v-it-needs-to-be-a-pe","errorCode":null,"errorMessage":"invalid tls cert value: '%#v', it needs to be a PEM formatted string","messagePattern":"invalid tls cert value: '%#v', it needs to be a PEM formatted string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/grpc/params.go","lineNumber":230,"sourceCode":"\t\tdefault:\n\t\t\treturn result, fmt.Errorf(\"unknown connect param: %q\", k)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc parseConnectTLSParam(params *connectParams, v any) error {\n\tvar ok bool\n\tparams.TLS, ok = v.(map[string]any)\n\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid tls value: '%#v', expected (optional) keys: cert, key, password, and cacerts\", v)\n\t}\n\t// optional map keys below\n\tif cert, certok := params.TLS[\"cert\"]; certok {\n\t\tif _, ok = cert.(string); !ok {\n\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',\"+","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/grpc/params.go#L212-L248","documentation":"Thrown by k6's gRPC Client.connect() when the tls.cert sub-option is present but not a string. parseConnectTLSParam (internal/js/modules/k6/grpc/params.go:228-231) only checks that cert is a Go string (a PEM-formatted client certificate); it does not validate that the PEM parses. Note a formatting quirk: the message interpolates v — the entire tls object — not just the cert value, so the printed value looks like a map.","triggerScenarios":"tls: { cert: 123 }, cert: { pem: '...' }, cert: ['...'], or passing an array of certificates. cert must be a single string; there is no array form for the client certificate.","commonSituations":"Confusing cacerts (which accepts a string OR array) with cert (string only); passing a parsed object or Buffer-like value instead of the raw PEM text read from a file.","solutions":["Ensure tls.cert is a single PEM string, e.g. cert: open('client.pem').readAll()?.toString() in newer k6, or an embedded template literal.","Keep the PEM headers (-----BEGIN CERTIFICATE-----) intact; do not base64-encode or JSON-wrap the value.","If you need multiple CA certificates, put them in cacerts (string or array), not cert.","Ignore the map-looking %#v in the message — it is the whole tls value; check only your cert entry's type."],"exampleFix":"// before\nclient.connect('host:443', { tls: { cert: [certPem] } });\n\n// after\nclient.connect('host:443', { tls: { cert: certPem, key: keyPem } });","handlingStrategy":"validation","validationCode":"function validateTls(tls = {}) {\n  if ('cert' in tls && typeof tls.cert !== 'string') throw new Error('tls.cert must be a PEM string');\n}","typeGuard":"const isPemString = (v) => typeof v === 'string' && /-----BEGIN [^-]+-----/.test(v);","tryCatchPattern":null,"preventionTips":["Only cacerts accepts arrays; cert and key are single strings.","Read PEM files once at init and assert they begin with '-----BEGIN'."],"tags":["grpc","tls","validation","client-cert"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}