{"record":{"id":"8cf6de978431b3ab","repo":"cloudflare/cloudflared","slug":"failed-to-write-org-token-to-disk","errorCode":null,"errorMessage":"failed to write org token to disk","messagePattern":"failed to write org token to disk","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"token/token.go","lineNumber":408,"sourceCode":"func getTokensFromEdge(appURL *url.URL, appAUD, appTokenPath, orgTokenPath string, useHostOnly bool, autoClose bool, isFedramp bool, log *zerolog.Logger) (string, error) {\n\t// If no org token exists or if it couldn't be exchanged for an app token, then run the transfer service flow.\n\n\t// this weird parameter is the resource name (token) and the key/value\n\t// we want to send to the transfer service. the key is token and the value\n\t// is blank (basically just the id generated in the transfer service)\n\tresourceData, err := RunTransfer(appURL, appAUD, keyName, keyName, \"\", true, useHostOnly, autoClose, isFedramp, log, appTokenPath+\".url\")\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to run transfer service\")\n\t}\n\tvar resp transferServiceResponse\n\tif err = json.Unmarshal(resourceData, &resp); err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to marshal transfer service response\")\n\t}\n\n\t// If we were able to get the auth domain and generate an org token path, lets write it to disk.\n\tif orgTokenPath != \"\" {\n\t\tif err := os.WriteFile(orgTokenPath, []byte(resp.OrgToken), 0600); err != nil {\n\t\t\treturn \"\", errors.Wrap(err, \"failed to write org token to disk\")\n\t\t}\n\t}\n\n\tif err := os.WriteFile(appTokenPath, []byte(resp.AppToken), 0600); err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to write app token to disk\")\n\t}\n\n\treturn resp.AppToken, nil\n}\n\n// GetAppInfo discovers the Access application protecting reqURL by requesting\n// a signed metadata JWT from the Cloudflare edge. The JWT signature is verified\n// against the account's public keys (fetched from the auth domain's JWKS\n// endpoint) to prevent an attacker-controlled server from spoofing app identity.\nfunc GetAppInfo(reqURL *url.URL) (*AppInfo, error) {\n\t// Fetch the metadata JWT from the edge (no redirects followed).\n\trawJWT, err := fetchMetadataJWT(reqURL.String())\n\tif err != nil {","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/token/token.go#L390-L426","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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')"],"exampleFix":"// before: writing to a path whose directory may not exist\nif err := os.WriteFile(orgTokenPath, []byte(resp.OrgToken), 0600); err != nil {\n\treturn \"\", errors.Wrap(err, \"failed to write org token to disk\")\n}\n// after: ensure parent directory exists and is writable first\nif err := os.MkdirAll(filepath.Dir(orgTokenPath), 0700); err != nil {\n\treturn \"\", errors.Wrap(err, \"failed to create token directory\")\n}\nif err := os.WriteFile(orgTokenPath, []byte(resp.OrgToken), 0600); err != nil {\n\treturn \"\", errors.Wrap(err, \"failed to write org token to disk\")\n}","handlingStrategy":"try-catch","validationCode":"if info, err := os.Stat(filepath.Dir(tokenPath)); err != nil || !info.IsDir() {\n\tos.MkdirAll(filepath.Dir(tokenPath), 0700)\n}\nif err := unix.Access(filepath.Dir(tokenPath), unix.W_OK); err != nil {\n\t// directory not writable by current user\n}","typeGuard":null,"tryCatchPattern":"token, err := getToken(ctx, log)\nif err != nil && strings.Contains(err.Error(), \"failed to write org token to disk\") {\n\t// fix token dir permissions or fall back to non-persistent auth\n}","preventionTips":["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"],"tags":["filesystem","token","persistence","permissions"],"backgroundTag":"file-write-failed","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}