cloudflare/cloudflared · error

Failed to fetch page. Server returned: %d

Error message

Failed to fetch page. Server returned: %d

What it means

fetchPage returns this error when fetching a paginated result page yields an unexpected HTTP status that is neither a successful response nor one of the mapped sentinel codes. The message embeds the raw status code so the developer can see exactly what the server returned. It effectively means the pagination loop hit an unrecognized or failed server response.

Source

Thrown at cfapi/base_client.go:180

	}
	return fullResponse, nil
}

func fetchPage[T any](requestFn func(int) (*http.Response, error), page int) (*response, []*T, error) {
	pageResp, err := requestFn(page)
	if err != nil {
		return nil, nil, errors.Wrap(err, "REST request failed")
	}
	defer pageResp.Body.Close()
	if pageResp.StatusCode == http.StatusOK {
		envelope, err := parseResponseEnvelope(pageResp.Body)
		if err != nil {
			return nil, nil, err
		}
		var parsedRspBody []*T
		return envelope, parsedRspBody, parseResponseBody(envelope, &parsedRspBody)
	}
	return nil, nil, errors.New(fmt.Sprintf("Failed to fetch page. Server returned: %d", pageResp.StatusCode))
}

type response struct {
	Success    bool            `json:"success,omitempty"`
	Errors     []apiError      `json:"errors,omitempty"`
	Messages   []string        `json:"messages,omitempty"`
	Result     json.RawMessage `json:"result,omitempty"`
	Pagination Pagination      `json:"result_info,omitempty"`
}

type Pagination struct {
	Count      int `json:"count,omitempty"`
	Page       int `json:"page,omitempty"`
	PerPage    int `json:"per_page,omitempty"`
	TotalCount int `json:"total_count,omitempty"`
}

func (r *response) checkErrors() error {

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Read the embedded status code: 429/5xx warrant a retry with backoff, 4xx indicates request problems
  2. Add retry-with-backoff around the listing call for 5xx/429 statuses
  3. Check the Cloudflare status page for API incidents if failures persist
  4. Log the response body (if available) for statuses not mapped to sentinels

Example fix

// before
tunnels, err := client.ListTunnels(ctx, accountTag)
if err != nil {
    return err
}
// after
tunnels, err := client.ListTunnels(ctx, accountTag)
if err != nil {
    if retriable(err) { // e.g. status 429 or 5xx in message
        time.Sleep(backoff)
        tunnels, err = client.ListTunnels(ctx, accountTag)
    }
    if err != nil {
        return err
    }
}
Defensive patterns

Strategy: retry

Try / catch

err := doList(ctx)
if err != nil {
    var status int
    if n, _ := fmt.Sscanf(err.Error(), "Failed to fetch page. Server returned: %d", &status); n == 1 && (status == 429 || status >= 500) {
        // exponential backoff retry
    }
}

Prevention

When it happens

Trigger: Calling any paginated listing API (e.g. ListTunnels) where the server responds with a status other than 200 and the codes handled by statusCodeToError (401/400/404 etc.) — e.g. 500, 502, 503, 429 from Cloudflare.

Common situations: Cloudflare API incidents or maintenance windows; rate limiting (429) during bulk listings; proxies/CDNs injecting error pages; very large account listings triggering server errors.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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