{"record":{"id":"28d4baec6feea3e6","repo":"cloudflare/cloudflared","slug":"found-multiple-tokens-in-the-certificate","errorCode":null,"errorMessage":"found multiple tokens in the certificate","messagePattern":"found multiple tokens in the certificate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/origin_cert.go","lineNumber":95,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"pem encoding failed: %v\", err)\n\t}\n\treturn out.Bytes(), nil\n}\n\nfunc decodeOriginCert(blocks []byte) (*OriginCert, error) {\n\tif len(blocks) == 0 {\n\t\treturn nil, fmt.Errorf(\"cannot decode empty certificate\")\n\t}\n\toriginCert := OriginCert{}\n\tblock, rest := pem.Decode(blocks)\n\tfor block != nil {\n\t\tswitch block.Type {\n\t\tcase \"PRIVATE KEY\", \"CERTIFICATE\":\n\t\t\t// this is for legacy purposes.\n\t\tcase \"ARGO TUNNEL TOKEN\":\n\t\t\tif originCert.ZoneID != \"\" || originCert.APIToken != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"found multiple tokens in the certificate\")\n\t\t\t}\n\t\t\t// The token is a string,\n\t\t\t// Try the newer JSON format\n\t\t\t_ = json.Unmarshal(block.Bytes, &originCert)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown block %s in the certificate\", block.Type)\n\t\t}\n\t\tblock, rest = pem.Decode(rest)\n\t}\n\n\tif originCert.ZoneID == \"\" || originCert.APIToken == \"\" {\n\t\treturn nil, fmt.Errorf(\"missing token in the certificate\")\n\t}\n\n\treturn &originCert, nil\n}\n\nfunc readOriginCert(originCertPath string) ([]byte, error) {","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/credentials/origin_cert.go#L77-L113","documentation":"Certificate-parsing error in decodeOriginCert: the origin cert PEM bundle contains more than one 'ARGO TUNNEL TOKEN' block. Only a single token block is valid; a second one means the file was concatenated or corrupted, and loading it is refused to avoid ambiguous credentials.","triggerScenarios":"PEM bundle passed to decodeOriginCert contains two or more 'ARGO TUNNEL TOKEN' blocks (second hit when originCert.ZoneID or originCert.APIToken is already set from a prior token block).","commonSituations":"Manually concatenated cert files; automation that appends tokens instead of replacing them; stale plus renewed token bundled in one .pem.","solutions":["Open the cert file and remove duplicate 'ARGO TUNNEL TOKEN' blocks, keeping only the current one","Re-run 'cloudflared tunnel login' to regenerate a clean cert.pem","Ensure deploy tooling overwrites rather than appends to the credentials file"],"exampleFix":"// before\ncat old-cert.pem new-cert.pem > cert.pem\n// after\ncp new-cert.pem cert.pem  # keep exactly one ARGO TUNNEL TOKEN block","handlingStrategy":"validation","validationCode":"count := strings.Count(string(pemBytes), \"ARGO TUNNEL TOKEN\")\nif count > 1 { return errors.New(\"cert file has multiple token blocks\") }","typeGuard":"func hasSingleTokenBlock(pemBytes []byte) bool {\n\tseen := 0\n\trest := pemBytes\n\tfor {\n\t\tvar b *pem.Block\n\t\tb, rest = pem.Decode(rest)\n\t\tif b == nil { return seen == 1 }\n\t\tif b.Type == \"ARGO TUNNEL TOKEN\" { seen++ }\n\t}\n}","tryCatchPattern":"cert, err := credentials.DecodeOriginCert(blocks)\nif err != nil && strings.Contains(err.Error(), \"multiple tokens\") {\n\t// flag file for manual cleanup / regenerate\n}","preventionTips":["Never concatenate cert files; overwrite instead","Regenerate via 'cloudflared tunnel login' rather than hand-editing","Lint PEM bundles in CI for duplicate token blocks"],"tags":["pem","certificate","duplicate"],"backgroundTag":"invalid-argument-value","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}