cloudflare/cloudflared · error

failed to create account level endpoint

Error message

failed to create account level endpoint

What it means

NewRESTClient builds the Cloudflare API account-level cfd_tunnel endpoint URL with url.Parse and wraps any parse failure with this message. It means the constructed URL string (baseURL + /accounts/<accountTag>/cfd_tunnel) was not a valid URL. This happens almost exclusively when baseURL or accountTag contain characters illegal in a URL.

Source

Thrown at cfapi/base_client.go:51

	userAgent     string
	client        http.Client
	log           *zerolog.Logger
}

type baseEndpoints struct {
	accountLevel  url.URL
	zoneLevel     url.URL
	accountRoutes url.URL
	accountVnets  url.URL
}

var _ Client = (*RESTClient)(nil)

func NewRESTClient(baseURL, accountTag, zoneTag, authToken, userAgent string, log *zerolog.Logger) (*RESTClient, error) {
	baseURL = strings.TrimSuffix(baseURL, "/")
	accountLevelEndpoint, err := url.Parse(fmt.Sprintf("%s/accounts/%s/cfd_tunnel", baseURL, accountTag))
	if err != nil {
		return nil, errors.Wrap(err, "failed to create account level endpoint")
	}
	accountRoutesEndpoint, err := url.Parse(fmt.Sprintf("%s/accounts/%s/teamnet/routes", baseURL, accountTag))
	if err != nil {
		return nil, errors.Wrap(err, "failed to create route account-level endpoint")
	}
	accountVnetsEndpoint, err := url.Parse(fmt.Sprintf("%s/accounts/%s/teamnet/virtual_networks", baseURL, accountTag))
	if err != nil {
		return nil, errors.Wrap(err, "failed to create virtual network account-level endpoint")
	}
	zoneLevelEndpoint, err := url.Parse(fmt.Sprintf("%s/zones/%s/tunnels", baseURL, zoneTag))
	if err != nil {
		return nil, errors.Wrap(err, "failed to create account level endpoint")
	}
	httpTransport := http.Transport{
		TLSHandshakeTimeout:   defaultTimeout,
		ResponseHeaderTimeout: defaultTimeout,
	}
	_ = http2.ConfigureTransport(&httpTransport)

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Print/inspect baseURL and accountTag; trim whitespace and remove illegal characters.
  2. Use the default Cloudflare API URL (https://api.cloudflare.com) unless you specifically need a proxy.
  3. URL-escape the account tag if it can contain special characters.
  4. Validate the account tag matches the expected hex-ID format before constructing the client.

Example fix

// before
NewRESTClient("https://api.cloudflare.com ", accountTag, ...)
// after
NewRESTClient(strings.TrimSpace(baseURL), strings.TrimSpace(accountTag), ...)
Defensive patterns

Strategy: validation

Validate before calling

if u, err := url.Parse(strings.TrimSpace(baseURL)); err != nil || u.Scheme == "" || u.Host == "" {
	return fmt.Errorf("invalid API base URL: %q", baseURL)
}
if strings.TrimSpace(accountTag) == "" {
	return errors.New("account tag must not be empty")
}

Try / catch

client, err := cfapi.NewRESTClient(baseURL, accountTag, zoneTag, token, ua, log)
if err != nil {
	return fmt.Errorf("failed to init cfapi client (check baseURL/accountTag): %w", err)
}

Prevention

When it happens

Trigger: Calling NewRESTClient with a baseURL containing spaces or control characters, or an accountTag with unencoded special characters (spaces, '%', non-ASCII).

Common situations: A typo or trailing whitespace in the API base URL config, copying the account tag with extra characters from a shell/JSON output, or overriding the default API host with a malformed custom value (e.g. in a test or proxy setup).

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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