{"record":{"id":"aa9682a9c530843e","repo":"cloudflare/cloudflared","slug":"cannot-decode-empty-certificate","errorCode":null,"errorMessage":"cannot decode empty certificate","messagePattern":"cannot decode empty certificate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/origin_cert.go","lineNumber":85,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"originCert marshal failed: %v\", err)\n\t}\n\tblock := pem.Block{\n\t\tType:    \"ARGO TUNNEL TOKEN\",\n\t\tHeaders: map[string]string{},\n\t\tBytes:   buffer,\n\t}\n\tvar out bytes.Buffer\n\terr = pem.Encode(&out, &block)\n\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)","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/credentials/origin_cert.go#L67-L103","documentation":"decodeOriginCert parses a PEM bundle into an OriginCert. When the input byte slice is empty there are no PEM blocks to decode, so the function fails fast with this error rather than returning a useless empty cert.","triggerScenarios":"Calling credentials/origin_cert.go decodeOriginCert (directly or via Read/DecodeOriginCert) with a nil or zero-length []byte, e.g. after readOriginCert returned empty content.","commonSituations":"Tunnel credentials file at --origincert path is empty or truncated (disk full during write, mount issue, download interrupted); user points at a zero-byte file.","solutions":["Check the origin cert file exists and has non-zero size before decoding (os.Stat, size > 0)","Re-download/regenerate the origin cert from Cloudflare (cloudflared tunnel login)","Verify the --origincert flag points to the correct file, not a placeholder"],"exampleFix":"// before\ncert, _ := credentials.DecodeOriginCert(blocks)\n// after\nif len(blocks) == 0 {\n\treturn fmt.Errorf(\"origin cert file is empty; re-run 'cloudflared tunnel login'\")\n}\ncert, err := credentials.DecodeOriginCert(blocks)","handlingStrategy":"validation","validationCode":"fi, err := os.Stat(certPath)\nif err != nil || fi.Size() == 0 {\n\treturn fmt.Errorf(\"origin cert %s missing or empty\", certPath)\n}","typeGuard":"func hasCertData(blocks []byte) bool { return len(blocks) > 0 }","tryCatchPattern":"cert, err := credentials.DecodeOriginCert(blocks)\nif err != nil && strings.Contains(err.Error(), \"cannot decode empty certificate\") {\n\t// prompt re-login / regenerate cert\n}","preventionTips":["Check file size > 0 before decoding","Atomic-write credential files (temp + rename) so they are never partially empty","Alert on empty cert files in deploy pipelines"],"tags":["pem","certificate","credentials"],"backgroundTag":"empty-required-field","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}