cloudflare/cloudflared · error

couldn't read tunnel credentials from %v

Error message

couldn't read tunnel credentials from %v

What it means

readTunnelCredentials could not read the tunnel credentials file from disk. The resolved path (via credFinder) exists logically per the finder, but reading its bytes failed. The message includes the offending file path.

Source

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

func (sc *subcommandContext) credential() (*credentials.User, error) {
	if sc.userCredential == nil {
		uc, err := credentials.Read(sc.c.String(cfdflags.OriginCert), sc.log)
		if err != nil {
			return nil, err
		}
		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 {

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Verify the path printed in the error exists: `ls -l <path>`
  2. Fix permissions so the cloudflared process user can read it (e.g. `chown`/`chmod 600`)
  3. Re-run `cloudflared tunnel token <name>` to regenerate the credentials JSON file
  4. If the file is truly gone, delete and recreate the tunnel: `cloudflared tunnel create <name>`
  5. In containers, ensure the credentials file is mounted into the container

Example fix

// before
cloudflared tunnel run --cred-file /etc/cloudflared/wrong.json mytunnel
// after
cloudflared tunnel run --cred-file /etc/cloudflared/mytunnel.json mytunnel
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(credPath); err != nil {
    return fmt.Errorf("credentials file missing/unreadable: %w", err)
}
if f, err := os.Open(credPath); err != nil {
    return fmt.Errorf("no read permission for %s: %w", credPath, err)
} else { f.Close() }

Try / catch

if err := runTunnel(...); err != nil {
    if strings.Contains(err.Error(), "couldn't read tunnel credentials") {
        // check path exists and re-provision token before crashing
    }
    return err
}

Prevention

When it happens

Trigger: sc.fs.readFile(filePath) fails in readTunnelCredentials, reached from `cloudflared tunnel tunnel run <name>` (findCredentials) or `tunnel info`/delete flows via findID, when the --cred-file path is unreadable.

Common situations: Credentials file deleted or moved after tunnel creation; wrong path passed via --cred-file; running cloudflared as a different user (systemd service) lacking read permission; Docker/container volume not mounted.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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