cloudflare/cloudflared · error

create token file at %s: %w

Error message

create token file at %s: %w

What it means

createTokenFileUnix opens (or creates) the token file with os.OpenFile(O_RDWR|O_CREATE, 0600). A failure is wrapped as 'create token file at <path>: <cause>'. This means the token file could not be opened or created, typically due to permissions, a read-only filesystem, or the path being a directory.

Source

Thrown at cmd/cloudflared/common_service.go:34

const (
	defaultTokenFile = "token"
)

func ensureConfigDirExists(configDir string) error {
	if err := os.Mkdir(configDir, 0o755); err != nil { //nolint:gosec // config dir must be traversable by non-root user
		if errors.Is(err, os.ErrExist) {
			return nil
		}
		return fmt.Errorf("create config dir at %s: %w", configDir, err)
	}
	return nil
}

func createTokenFileUnix(path string) error {
	const tokenPerms os.FileMode = 0o600
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, tokenPerms) //nolint:gosec // All callers of this function construct path from constant strings or well-known env vars (e.g., $HOME)
	if err != nil {
		return fmt.Errorf("create token file at %s: %w", path, err)
	}
	defer func() { _ = f.Close() }()

	// If the file already existed with unrestrictive permissions, os.OpenFile
	// will not update its permissions, so perform an extra os.Chmod
	if err := os.Chmod(path, tokenPerms); err != nil {
		return fmt.Errorf("chmod token file at %s: %w", path, err)
	}

	return nil
}

// Write out the token file to the configuration directory with the correct
// permissions. Since the method used to restrict the permissions is platform
// dependent, make the function used to restrict the permissions an injectable
// dependency
func writeTokenToFile(path string, token string) error {
	if _, err := tunnel.ParseToken(token); err != nil {

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Run the command with sufficient privileges (sudo) or point --cred-file at a user-writable path
  2. Check that the target path is not an existing directory and remove/rename it
  3. Verify the filesystem is writable (mount flags, disk space)
  4. Check SELinux/AppArmor audit logs if permissions look correct

Example fix

// before
cloudflared tunnel token --cred-file /etc/cloudflared/token.json TUNNEL_ID
// after
sudo cloudflared tunnel token --cred-file /etc/cloudflared/token.json TUNNEL_ID
Defensive patterns

Strategy: try-catch

Validate before calling

if info, err := os.Stat(path); err == nil {
    if info.IsDir() {
        return fmt.Errorf("token path %s is a directory", path)
    }
} else if !os.IsNotExist(err) {
    return err
}
if err := unix.Access(filepath.Dir(path), unix.W_OK); err != nil {
    return fmt.Errorf("cannot write in %s", filepath.Dir(path))
}

Try / catch

if err := createTokenFileUnix(path); err != nil {
    var pathErr *os.PathError
    if errors.As(err, &pathErr) && (errors.Is(pathErr.Err, syscall.EACCES) || errors.Is(pathErr.Err, syscall.EPERM)) {
        return fmt.Errorf("permission denied creating %s; try sudo or a writable --cred-file", path)
    }
    return err
}

Prevention

When it happens

Trigger: The parent directory is not writable by the current user; the path exists as a directory; the filesystem is read-only; SELinux/AppArmor denies the open.

Common situations: Writing the token into /etc/cloudflared without sudo; containers with read-only rootfs; a directory was accidentally created at the token file path; disk-full edge cases on create.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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