cloudflare/cloudflared · error

found multiple tokens in the certificate

Error message

found multiple tokens in the certificate

What it means

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.

Source

Thrown at credentials/origin_cert.go:95

	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)
	}

	if originCert.ZoneID == "" || originCert.APIToken == "" {
		return nil, fmt.Errorf("missing token in the certificate")
	}

	return &originCert, nil
}

func readOriginCert(originCertPath string) ([]byte, error) {

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Open the cert file and remove duplicate 'ARGO TUNNEL TOKEN' blocks, keeping only the current one
  2. Re-run 'cloudflared tunnel login' to regenerate a clean cert.pem
  3. Ensure deploy tooling overwrites rather than appends to the credentials file

Example fix

// before
cat old-cert.pem new-cert.pem > cert.pem
// after
cp new-cert.pem cert.pem  # keep exactly one ARGO TUNNEL TOKEN block
Defensive patterns

Strategy: validation

Validate before calling

count := strings.Count(string(pemBytes), "ARGO TUNNEL TOKEN")
if count > 1 { return errors.New("cert file has multiple token blocks") }

Type guard

func hasSingleTokenBlock(pemBytes []byte) bool {
	seen := 0
	rest := pemBytes
	for {
		var b *pem.Block
		b, rest = pem.Decode(rest)
		if b == nil { return seen == 1 }
		if b.Type == "ARGO TUNNEL TOKEN" { seen++ }
	}
}

Try / catch

cert, err := credentials.DecodeOriginCert(blocks)
if err != nil && strings.Contains(err.Error(), "multiple tokens") {
	// flag file for manual cleanup / regenerate
}

Prevention

When it happens

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

Common situations: Manually concatenated cert files; automation that appends tokens instead of replacing them; stale plus renewed token bundled in one .pem.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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