cloudflare/cloudflared · error
failed to write org token to disk
Error message
failed to write org token to disk
What it means
This error wraps a failure from os.WriteFile when persisting the Cloudflare Access org token to the token path on disk after successfully fetching tokens from the edge. The library throws it because without the org token cached on disk, subsequent runs cannot reuse the org token to exchange for app tokens, breaking the token refresh flow. The underlying err carries the real OS-level cause (permissions, missing directory, disk full).
Source
Thrown at token/token.go:408
func getTokensFromEdge(appURL *url.URL, appAUD, appTokenPath, orgTokenPath string, useHostOnly bool, autoClose bool, isFedramp bool, log *zerolog.Logger) (string, error) {
// If no org token exists or if it couldn't be exchanged for an app token, then run the transfer service flow.
// this weird parameter is the resource name (token) and the key/value
// we want to send to the transfer service. the key is token and the value
// is blank (basically just the id generated in the transfer service)
resourceData, err := RunTransfer(appURL, appAUD, keyName, keyName, "", true, useHostOnly, autoClose, isFedramp, log, appTokenPath+".url")
if err != nil {
return "", errors.Wrap(err, "failed to run transfer service")
}
var resp transferServiceResponse
if err = json.Unmarshal(resourceData, &resp); err != nil {
return "", errors.Wrap(err, "failed to marshal transfer service response")
}
// If we were able to get the auth domain and generate an org token path, lets write it to disk.
if orgTokenPath != "" {
if err := os.WriteFile(orgTokenPath, []byte(resp.OrgToken), 0600); err != nil {
return "", errors.Wrap(err, "failed to write org token to disk")
}
}
if err := os.WriteFile(appTokenPath, []byte(resp.AppToken), 0600); err != nil {
return "", errors.Wrap(err, "failed to write app token to disk")
}
return resp.AppToken, nil
}
// GetAppInfo discovers the Access application protecting reqURL by requesting
// a signed metadata JWT from the Cloudflare edge. The JWT signature is verified
// against the account's public keys (fetched from the auth domain's JWKS
// endpoint) to prevent an attacker-controlled server from spoofing app identity.
func GetAppInfo(reqURL *url.URL) (*AppInfo, error) {
// Fetch the metadata JWT from the edge (no redirects followed).
rawJWT, err := fetchMetadataJWT(reqURL.String())
if err != nil {View on GitHub (pinned to 2253eeeb25)
Solutions
- Check that the directory containing orgTokenPath exists and is writable by the current user (ls -ld on the parent dir); create it with mkdir -p if missing
- Re-run as the same user that owns the token directory, or with correct ownership (chown) / appropriate privileges
- Check disk space (df -h) and filesystem mount status (read-only mounts)
- If running in a container, mount a writable volume for the token path or set a writable token directory
- Inspect the wrapped cause in the error message for the exact OS error (e.g. 'permission denied', 'no such file or directory')
Example fix
// before: writing to a path whose directory may not exist
if err := os.WriteFile(orgTokenPath, []byte(resp.OrgToken), 0600); err != nil {
return "", errors.Wrap(err, "failed to write org token to disk")
}
// after: ensure parent directory exists and is writable first
if err := os.MkdirAll(filepath.Dir(orgTokenPath), 0700); err != nil {
return "", errors.Wrap(err, "failed to create token directory")
}
if err := os.WriteFile(orgTokenPath, []byte(resp.OrgToken), 0600); err != nil {
return "", errors.Wrap(err, "failed to write org token to disk")
} Defensive patterns
Strategy: try-catch
Validate before calling
if info, err := os.Stat(filepath.Dir(tokenPath)); err != nil || !info.IsDir() {
os.MkdirAll(filepath.Dir(tokenPath), 0700)
}
if err := unix.Access(filepath.Dir(tokenPath), unix.W_OK); err != nil {
// directory not writable by current user
} Try / catch
token, err := getToken(ctx, log)
if err != nil && strings.Contains(err.Error(), "failed to write org token to disk") {
// fix token dir permissions or fall back to non-persistent auth
} Prevention
- Ensure the token directory exists and is owned by the service user before first login
- Run cloudflared/access commands as a consistent user
- Mount a writable volume for token storage in containers
- Monitor disk space on hosts running cloudflared
When it happens
Trigger: getTokensFromEdge (via getToken) successfully authenticated and got resp.OrgToken from the edge, orgTokenPath was non-empty, but os.WriteFile(orgTokenPath, ...) failed — typically because the parent directory does not exist or is not writable by the current user.
Common situations: Running cloudflared/cloudflared-access as a different user than the one who first authenticated; token dir under $HOME of another user or read-only filesystem; container running as non-root without a writable TUNNEL_TOKEN dir; full disk; overly restrictive umask/SELinux policy.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- failed to create lock file %s
- failed to acquire app token lock
- failed to acquire org token lock
- failed to write app token to disk
- The file-writing error is: %v / The delete tunnel error is:
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/8cf6de978431b3ab.
Report an issue: GitHub.