cloudflare/cloudflared · error

cannot decode empty certificate

Error message

cannot decode empty certificate

What it means

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.

Source

Thrown at credentials/origin_cert.go:85

	if err != nil {
		return nil, fmt.Errorf("originCert marshal failed: %v", err)
	}
	block := pem.Block{
		Type:    "ARGO TUNNEL TOKEN",
		Headers: map[string]string{},
		Bytes:   buffer,
	}
	var out bytes.Buffer
	err = pem.Encode(&out, &block)
	if err != nil {
		return nil, fmt.Errorf("pem encoding failed: %v", err)
	}
	return out.Bytes(), nil
}

func decodeOriginCert(blocks []byte) (*OriginCert, error) {
	if len(blocks) == 0 {
		return nil, fmt.Errorf("cannot decode empty certificate")
	}
	originCert := OriginCert{}
	block, rest := pem.Decode(blocks)
	for block != nil {
		switch block.Type {
		case "PRIVATE KEY", "CERTIFICATE":
			// this is for legacy purposes.
		case "ARGO TUNNEL TOKEN":
			if originCert.ZoneID != "" || originCert.APIToken != "" {
				return nil, fmt.Errorf("found multiple tokens in the certificate")
			}
			// The token is a string,
			// Try the newer JSON format
			_ = json.Unmarshal(block.Bytes, &originCert)
		default:
			return nil, fmt.Errorf("unknown block %s in the certificate", block.Type)
		}
		block, rest = pem.Decode(rest)

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Check the origin cert file exists and has non-zero size before decoding (os.Stat, size > 0)
  2. Re-download/regenerate the origin cert from Cloudflare (cloudflared tunnel login)
  3. Verify the --origincert flag points to the correct file, not a placeholder

Example fix

// before
cert, _ := credentials.DecodeOriginCert(blocks)
// after
if len(blocks) == 0 {
	return fmt.Errorf("origin cert file is empty; re-run 'cloudflared tunnel login'")
}
cert, err := credentials.DecodeOriginCert(blocks)
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(certPath)
if err != nil || fi.Size() == 0 {
	return fmt.Errorf("origin cert %s missing or empty", certPath)
}

Type guard

func hasCertData(blocks []byte) bool { return len(blocks) > 0 }

Try / catch

cert, err := credentials.DecodeOriginCert(blocks)
if err != nil && strings.Contains(err.Error(), "cannot decode empty certificate") {
	// prompt re-login / regenerate cert
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/aa9682a9c530843e. Report an issue: GitHub.