cloudflare/cloudflared · error

failed to acquire org token lock

Error message

failed to acquire org token lock

What it means

getToken wraps this error when acquireLockFile fails to create the org-token lock file with a non-EEXIST error. The org lock ensures only one process performs the org-token exchange and subsequent app-token write for the auth domain. Without the lock, the exchange flow aborts.

Source

Thrown at token/token.go:368

	defer appTokenLock.release()

	// check to see if another process has gotten a token while we waited for the lock
	if token, err := GetAppTokenIfExists(appInfo); token != "" && err == nil {
		return token, nil
	}

	// If an app token couldn't be found on disk, check for an org token and attempt to exchange it for an app token.
	var orgTokenPath string
	orgToken, orgTokenErr := GetOrgTokenIfExists(appInfo.AuthDomain)
	if orgTokenErr != nil {
		orgTokenPath, err = generateOrgTokenFilePathFromURL(appInfo.AuthDomain)
		if err != nil {
			return "", errors.Wrap(err, "failed to generate org token file path")
		}

		orgTokenLock, orgLockErr := acquireLockFile(orgTokenPath, log)
		if orgLockErr != nil {
			return "", errors.Wrap(orgLockErr, "failed to acquire org token lock")
		}
		defer orgTokenLock.release()
		// check if an org token has been created since the lock was acquired
		orgToken, orgTokenErr = GetOrgTokenIfExists(appInfo.AuthDomain)
	}
	if orgTokenErr == nil {
		if appToken, exchangeErr := exchangeOrgToken(appURL, orgToken); exchangeErr != nil {
			log.Debug().Msgf("failed to exchange org token for app token: %s", exchangeErr)
		} else {
			// generate app path
			if err := os.WriteFile(appTokenPath, []byte(appToken), 0600); err != nil { // nolint: gosec
				return "", errors.Wrap(err, "failed to write app token to disk")
			}
			return appToken, nil
		}
	}
	return getTokensFromEdge(appURL, appInfo.AppAUD, appTokenPath, orgTokenPath, useHostOnly, autoClose, isFedramp, log)
}

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Ensure the token directory exists and is writable by the running user (mkdir -p, chown)
  2. Run cloudflared consistently under one user; fix ownership after any sudo runs
  3. Check disk space and mount flags (df -h, mount | grep home)
  4. Read the wrapped cause for the precise errno (EACCES/ENOENT/ENOSPC) and fix that condition

Example fix

// systemd unit: pin the user and pre-create the token dir
[Service]
User=cloudflared
ExecStartPre=/usr/bin/mkdir -p /home/cloudflared/.cloudflared
ExecStartPre=/bin/chown cloudflared:cloudflared /home/cloudflared/.cloudflared
Defensive patterns

Strategy: validation

Validate before calling

// preflight: directory exists, owned by me, writable
info, err := os.Stat(tokenDir)
if err != nil || !info.IsDir() {
	os.MkdirAll(tokenDir, 0700)
}
if err := syscall.Access(tokenDir, syscall.W_OK); err != nil {
	return fmt.Errorf("cannot write org-token lock in %s: %v", tokenDir, err)
}

Try / catch

token, err := FetchToken(...)
if err != nil && strings.Contains(err.Error(), "failed to acquire org token lock") {
	// filesystem-level failure; advise chown/mkdir, not retry
	return fmt.Errorf("%w — ensure %s is writable by the service user", err, tokenDir)
}

Prevention

When it happens

Trigger: FetchToken / FetchTokenWithRedirect -> getToken -> acquireLockFile(orgTokenPath) failing due to real filesystem errors: unwritable directory, missing parent directories, disk full, or restrictive umask/permissions on ~/.cloudflared.

Common situations: Multi-user systems where the daemon user differs from the user who created ~/.cloudflared; read-only container filesystems; NFS-mounted home directories with locking quirks; disk exhaustion on small VMs.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


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