cloudflare/cloudflared · error

The tunnel credentials file should be .json but you gave a .

Error message

The tunnel credentials file should be .json but you gave a .pem. The tunnel credentials file was originally created by `cloudflared tunnel create`. You may have accidentally used the filepath to cert.pem, which is generated by `cloudflared tunnel login`.

What it means

readTunnelCredentials parses the tunnel credentials file as JSON. If json.Unmarshal fails and the file has a .pem extension, cloudflared raises this dedicated error to tell you the wrong file was passed: credentials files (created by `cloudflared tunnel create`) are JSON, whereas cert.pem (created by `cloudflared tunnel login`) is a PEM certificate. The .pem check exists purely to produce this actionable hint instead of a generic invalid-JSON error.

Source

Thrown at cmd/cloudflared/tunnel/subcommand_context.go:116

		sc.userCredential = uc
	}
	return sc.userCredential, nil
}

func (sc *subcommandContext) readTunnelCredentials(credFinder CredFinder) (connection.Credentials, error) {
	filePath, err := credFinder.Path()
	if err != nil {
		return connection.Credentials{}, err
	}
	body, err := sc.fs.readFile(filePath)
	if err != nil {
		return connection.Credentials{}, errors.Wrapf(err, "couldn't read tunnel credentials from %v", filePath)
	}

	var credentials connection.Credentials
	if err = json.Unmarshal(body, &credentials); err != nil {
		if filepath.Ext(filePath) == ".pem" {
			return connection.Credentials{}, fmt.Errorf("The tunnel credentials file should be .json but you gave a .pem. " +
				"The tunnel credentials file was originally created by `cloudflared tunnel create`. " +
				"You may have accidentally used the filepath to cert.pem, which is generated by `cloudflared tunnel " +
				"login`.")
		}
		return connection.Credentials{}, invalidJSONCredentialError{path: filePath, err: err}
	}
	return credentials, nil
}

func (sc *subcommandContext) create(name string, credentialsFilePath string, secret string) (*cfapi.Tunnel, error) {
	client, err := sc.client()
	if err != nil {
		return nil, errors.Wrap(err, "couldn't create client to talk to Cloudflare Tunnel backend")
	}

	var tunnelSecret []byte
	if secret == "" {
		tunnelSecret, err = generateTunnelSecret()

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Run `cloudflared tunnel list` to find your tunnel, then point --credentials-file at <tunnel-id>.json in ~/.cloudflared (or ~/.cloudflared/config.json's credentials-file key).
  2. If no credentials JSON exists (tunnel created on another machine), recreate the tunnel with `cloudflared tunnel create <name>` to generate one.
  3. If you actually need to authenticate cloudflared itself, run `cloudflared tunnel login` to produce cert.pem — but never pass cert.pem as credentials-file.

Example fix

// before
cloudflared tunnel run --credentials-file ~/.cloudflared/cert.pem my-tunnel
// after
cloudflared tunnel run --credentials-file ~/.cloudflared/<tunnel-uuid>.json my-tunnel
Defensive patterns

Strategy: validation

Validate before calling

path := "~/.cloudflared/cert.pem" // whatever you'd pass
if filepath.Ext(path) == ".pem" {
    return fmt.Errorf("refusing to pass %s as credentials-file; expected a JSON file like <tunnel-id>.json", path)
}
if _, err := os.Stat(path); err != nil {
    return err
}

Prevention

When it happens

Trigger: Calling a tunnel command (e.g. `cloudflared tunnel run --credentials-file <path>`, or findCredentials/findID resolving credentials) with the path to cert.pem instead of <tunnel-id>.json.

Common situations: Developers pass ~/.cloudflared/cert.pem because it is the only file in ~/.cloudflared after running `cloudflared tunnel login`; shell autocompletion picks cert.pem; a script variables the wrong path in TUNNEL_CREDENTIALS.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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