cloudflare/cloudflared · error
Failed to fetch resource
Error message
Failed to fetch resource
What it means
transferRequest in token/transfer.go polls the Cloudflare Access CLI token-transfer endpoint up to 10 times ('long polling'), returning the payload as soon as a non-empty body arrives. If all 10 poll attempts complete with an empty body, it gives up with this sentinel error. It means the resource (the Access token) was never delivered to the transfer endpoint, i.e. the user never completed the browser login/authorization flow in time.
Source
Thrown at token/transfer.go:130
baseURL.RawQuery = q.Encode() // and this actual baseURL.
baseURL.Path = "cdn-cgi/access/cli"
return baseURL.String(), nil
}
// transferRequest downloads the requested resource from the request URL
func transferRequest(requestURL string, log *zerolog.Logger) ([]byte, string, error) {
client := &http.Client{Timeout: clientTimeout}
const pollAttempts = 10
// we do "long polling" on the endpoint to get the resource.
for i := 0; i < pollAttempts; i++ {
buf, key, err := poll(client, requestURL, log)
if err != nil {
return nil, "", err
} else if len(buf) > 0 {
return buf, key, nil
}
}
return nil, "", errors.New("Failed to fetch resource")
}
// poll the endpoint for the request resource, waiting for the user interaction
func poll(client *http.Client, requestURL string, log *zerolog.Logger) ([]byte, string, error) {
req, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, "", err
}
req.Header.Set(userAgentHeader, userAgent)
resp, err := client.Do(req) // nolint: gosec
if err != nil {
return nil, "", err
}
defer func() { _ = resp.Body.Close() }()
// ignore everything other than server errors as the resource
// may not exist until the user does the interaction
if resp.StatusCode >= 500 {View on GitHub (pinned to 2253eeeb25)
Solutions
- Re-run the command and complete the browser authentication flow promptly (click through SSO before polling finishes).
- Check that the browser successfully redirects back to the cdn-cgi/access/cli endpoint (watch for redirect errors or blocked popups).
- Verify network/proxy settings allow the machine to reach the Cloudflare Access transfer endpoint from both browser and CLI.
- Retry the login; if it recurs, increase the polling attempts/clientTimeout in token/transfer.go or capture zerolog debug output from poll() to see what the endpoint returns.
Example fix
// before: give up after fixed attempts
return nil, "", errors.New("Failed to fetch resource")
// after: give the user more time and a clearer message
const pollAttempts = 30
...
return nil, "", fmt.Errorf("did not receive token after %d polls; complete the browser login and retry", pollAttempts) Defensive patterns
Strategy: retry
Validate before calling
if requestURL == "" {
return fmt.Errorf("no transfer URL provided; run cloudflared access login first")
} Try / catch
buf, key, err := transferRequest(url, log)
if err != nil {
if err.Error() == "Failed to fetch resource" {
return fmt.Errorf("login not completed in time; rerun and finish browser auth: %w", err)
}
return err
} Prevention
- Complete the browser SSO promptly after launching the login command
- Run the CLI in an environment where the default browser can open and redirect back
- Check corporate proxies do not block the cdn-cgi/access/cli endpoint
- Retry once before diagnosing deeper — transient SSO delays commonly cause it
When it happens
Trigger: RunTransfer -> transferRequest exhausts pollAttempts=10 iterations of poll() where each HTTP GET on the request URL succeeds but returns an empty body. No network error occurred — the transfer service simply had no token to hand out within the polling window.
Common situations: Running `cloudflared access login` (or a flow that uses LoginHelper token transfer) and not completing the browser authentication before the poll loop ends; the user closing or abandoning the browser tab; corporate SSO taking longer than the polling budget; the redirect back to the CLI endpoint failing silently so the token is never stored.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- failed to accept QUIC stream: %w
- Failed to read auth methods: %v
- timeout waiting for second stream to finish
- failed to create tunnel
- did not receive ICMP echo reply
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/6f5f522a69caad8a.
Report an issue: GitHub.